mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-28 21:26:49 +00:00
Merge pull request #4467 from chewitt/amlogic-upstream
amlogic: bump to Linux 5.7.x
This commit is contained in:
commit
d51778bcf7
@ -128,14 +128,35 @@ else
|
||||
mixer $card Headphone 0db on
|
||||
mixer $card 'AIF1 Slot 0 Digital DAC' on
|
||||
|
||||
# Amlogic G12 HDMI to PCM0
|
||||
mixer $card 'FRDDR_A SINK 1 SEL' 'OUT 1'
|
||||
mixer $card 'FRDDR_A SRC 1 EN' on
|
||||
mixer $card 'TDMOUT_B SRC SEL' 'IN 0'
|
||||
mixer $card 'TOHDMITX I2S SRC' 'I2S B'
|
||||
mixer $card 'TOHDMITX' on
|
||||
# Amlogic G12 HDMI
|
||||
case $(dtname) in
|
||||
azw,gsking-x)
|
||||
mixer $card 'FRDDR_A SINK 1 SEL' 'OUT 0'
|
||||
mixer $card 'FRDDR_A SRC 1 EN' on
|
||||
mixer $card 'TDMOUT_A SRC SEL' 'IN 0'
|
||||
mixer $card 'FRDDR_B SINK 1 SEL' 'OUT 0'
|
||||
mixer $card 'FRDDR_B SRC 1 EN' on
|
||||
mixer $card 'TDMOUT_B SRC SEL' 'IN 0'
|
||||
mixer $card 'TOHDMITX' on
|
||||
mixer $card 'TOHDMITX I2S SRC' 'I2S A'
|
||||
;;
|
||||
khadas,vim3)
|
||||
mixer $card 'FRDDR_A SINK 1 SEL' 'OUT 0'
|
||||
mixer $card 'FRDDR_A SRC 1 EN' on
|
||||
mixer $card 'TDMOUT_A SRC SEL' 'IN 0'
|
||||
mixer $card 'TOHDMITX' on
|
||||
mixer $card 'TOHDMITX I2S SRC' 'I2S A'
|
||||
;;
|
||||
*)
|
||||
mixer $card 'FRDDR_A SINK 1 SEL' 'OUT 1'
|
||||
mixer $card 'FRDDR_A SRC 1 EN' on
|
||||
mixer $card 'TDMOUT_B SRC SEL' 'IN 0'
|
||||
mixer $card 'TOHDMITX' on
|
||||
mixer $card 'TOHDMITX I2S SRC' 'I2S B'
|
||||
;;
|
||||
esac
|
||||
|
||||
# Amlogic G12 S/PDIF to PCM1
|
||||
# Amlogic G12 S/PDIF
|
||||
mixer $card 'FRDDR_B SINK 1 SEL' 'OUT 3'
|
||||
mixer $card 'FRDDR_B SRC 1 EN' on
|
||||
mixer $card 'SPDIFOUT SRC SEL' 'IN 1'
|
||||
|
@ -2,11 +2,11 @@
|
||||
# Copyright (C) 2020-present Team LibreELEC (https://libreelec.tv)
|
||||
|
||||
PKG_NAME="qca-firmware"
|
||||
PKG_VERSION="39d025c6d52085c529568c4e110ca6d0b290fef6"
|
||||
PKG_SHA256="7af9e815f0cc5136819c9f7e02c548ea736d34c9a67ca065e5a693f4fdadb312"
|
||||
PKG_VERSION="09e2d02d9b767ec3aedf89ca11ff2bd9d94a96e0"
|
||||
PKG_SHA256="d068ef23a5d6401c9d0182575ecb50960da37689fe26394a0e2708cd4b0c0af0"
|
||||
PKG_LICENSE="QCA"
|
||||
PKG_URL="https://github.com/LibreELEC/qca-firmware/archive/$PKG_VERSION.tar.gz"
|
||||
PKG_LONGDESC="qca-firmware: WiFi/BT firmware for QCA9377 SDIO modules"
|
||||
PKG_LONGDESC="qca-firmware: BT firmware for QCA9377 SDIO modules"
|
||||
PKG_TOOLCHAIN="manual"
|
||||
|
||||
makeinstall_target() {
|
||||
|
@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=QCA Bluetooth Firmware Service
|
||||
ConditionPathExists=/dev/ttyAML1
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/hciattach -n -s 115200 /dev/ttyAML1 qca 2000000
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
StartLimitInterval=0
|
||||
LimitNPROC=1
|
||||
TimeoutStopSec=1s
|
@ -1,6 +0,0 @@
|
||||
########################################################
|
||||
# udev rules file for loading QCA9377 bluetooth firmware
|
||||
########################################################
|
||||
|
||||
ACTION=="add", SUBSYSTEMS=="sdio", ATTRS{vendor}=="0x0271", ATTRS{device}=="0x0701", \
|
||||
TAG+="systemd", ENV{SYSTEMD_WANTS}+="qca-firmware.service"
|
@ -15,13 +15,6 @@ PKG_STAMP="$KERNEL_TARGET $KERNEL_MAKE_EXTRACMD"
|
||||
PKG_PATCH_DIRS="$LINUX"
|
||||
|
||||
case "$LINUX" in
|
||||
amlogic)
|
||||
PKG_VERSION="98d54f81e36ba3bf92172791eba5ca5bd813989b" # 5.6-rc4
|
||||
PKG_SHA256="93d86760f8c2bc694c3a0ac6ceaa78034fe7d4026221d8480cd9696074d59a46"
|
||||
PKG_URL="https://github.com/torvalds/linux/archive/$PKG_VERSION.tar.gz"
|
||||
PKG_SOURCE_NAME="linux-$LINUX-$PKG_VERSION.tar.gz"
|
||||
PKG_PATCH_DIRS="amlogic"
|
||||
;;
|
||||
raspberrypi)
|
||||
PKG_VERSION="d00cdd80abb2a8c201cae2f6bd80e27eb2f7d347" # 5.4.45
|
||||
PKG_SHA256="4c6e5c458dfd07c8557afaedb54ad037f8d35c741f297a1b92ed796c69dec9de"
|
||||
|
@ -1,77 +0,0 @@
|
||||
From 42f3bbd03e5f991da0e42d827addc859f3b9b117 Mon Sep 17 00:00:00 2001
|
||||
From: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
||||
Date: Mon, 24 Feb 2020 02:01:13 +0000
|
||||
Subject: [PATCH 001/146] FROMLIST: drm/panfrost: Don't try to map on error
|
||||
faults
|
||||
|
||||
If the exception type isn't a translation fault, don't try to map and
|
||||
instead go straight to a terminal fault.
|
||||
|
||||
Otherwise, we can get flooded by kernel warnings and further faults.
|
||||
|
||||
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
|
||||
Signed-off-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
drivers/gpu/drm/panfrost/panfrost_mmu.c | 44 +++++++++++--------------
|
||||
1 file changed, 19 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
|
||||
index 3107b0738e40..5d75f8cf6477 100644
|
||||
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
|
||||
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
|
||||
@@ -601,33 +601,27 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
|
||||
source_id = (fault_status >> 16);
|
||||
|
||||
/* Page fault only */
|
||||
- if ((status & mask) == BIT(i)) {
|
||||
- WARN_ON(exception_type < 0xC1 || exception_type > 0xC4);
|
||||
-
|
||||
+ ret = -1;
|
||||
+ if ((status & mask) == BIT(i) && (exception_type & 0xF8) == 0xC0)
|
||||
ret = panfrost_mmu_map_fault_addr(pfdev, i, addr);
|
||||
- if (!ret) {
|
||||
- mmu_write(pfdev, MMU_INT_CLEAR, BIT(i));
|
||||
- status &= ~mask;
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
|
||||
- /* terminal fault, print info about the fault */
|
||||
- dev_err(pfdev->dev,
|
||||
- "Unhandled Page fault in AS%d at VA 0x%016llX\n"
|
||||
- "Reason: %s\n"
|
||||
- "raw fault status: 0x%X\n"
|
||||
- "decoded fault status: %s\n"
|
||||
- "exception type 0x%X: %s\n"
|
||||
- "access type 0x%X: %s\n"
|
||||
- "source id 0x%X\n",
|
||||
- i, addr,
|
||||
- "TODO",
|
||||
- fault_status,
|
||||
- (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
|
||||
- exception_type, panfrost_exception_name(pfdev, exception_type),
|
||||
- access_type, access_type_name(pfdev, fault_status),
|
||||
- source_id);
|
||||
+ if (ret)
|
||||
+ /* terminal fault, print info about the fault */
|
||||
+ dev_err(pfdev->dev,
|
||||
+ "Unhandled Page fault in AS%d at VA 0x%016llX\n"
|
||||
+ "Reason: %s\n"
|
||||
+ "raw fault status: 0x%X\n"
|
||||
+ "decoded fault status: %s\n"
|
||||
+ "exception type 0x%X: %s\n"
|
||||
+ "access type 0x%X: %s\n"
|
||||
+ "source id 0x%X\n",
|
||||
+ i, addr,
|
||||
+ "TODO",
|
||||
+ fault_status,
|
||||
+ (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
|
||||
+ exception_type, panfrost_exception_name(pfdev, exception_type),
|
||||
+ access_type, access_type_name(pfdev, fault_status),
|
||||
+ source_id);
|
||||
|
||||
mmu_write(pfdev, MMU_INT_CLEAR, mask);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,30 +0,0 @@
|
||||
From 72475ec15080b4a976c3815261723a91bb9a755b Mon Sep 17 00:00:00 2001
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
Date: Thu, 16 Jan 2020 21:11:53 +0800
|
||||
Subject: [PATCH 002/146] FROMGIT: drm/lima: update register info
|
||||
|
||||
From Mali r10p0 kernel driver source code.
|
||||
|
||||
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-2-yuq825@gmail.com
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_regs.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_regs.h b/drivers/gpu/drm/lima/lima_regs.h
|
||||
index ace8ecefbe90..0124c90e0153 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_regs.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_regs.h
|
||||
@@ -239,6 +239,7 @@
|
||||
#define LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4)
|
||||
#define LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5)
|
||||
#define LIMA_MMU_STATUS_BUS_ID(x) ((x >> 6) & 0x1F)
|
||||
+#define LIMA_MMU_STATUS_STALL_NOT_ACTIVE BIT(31)
|
||||
#define LIMA_MMU_COMMAND 0x0008
|
||||
#define LIMA_MMU_COMMAND_ENABLE_PAGING 0x00
|
||||
#define LIMA_MMU_COMMAND_DISABLE_PAGING 0x01
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,81 +0,0 @@
|
||||
From afbc6ad4851f6df5e6e0befa8d3fe8d664e688e7 Mon Sep 17 00:00:00 2001
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
Date: Thu, 16 Jan 2020 21:11:54 +0800
|
||||
Subject: [PATCH 003/146] FROMGIT: drm/lima: add lima_vm_map_bo
|
||||
|
||||
For dynamically mapping added backup memory of lima_bo to vm.
|
||||
This is a preparation for adding heap buffer support.
|
||||
|
||||
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-3-yuq825@gmail.com
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_vm.c | 42 ++++++++++++++++++++++++++++++++++
|
||||
drivers/gpu/drm/lima/lima_vm.h | 1 +
|
||||
2 files changed, 43 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c
|
||||
index 840e2350d872..2e513841de6c 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_vm.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_vm.c
|
||||
@@ -277,3 +277,45 @@ void lima_vm_print(struct lima_vm *vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff)
|
||||
+{
|
||||
+ struct lima_bo_va *bo_va;
|
||||
+ struct sg_dma_page_iter sg_iter;
|
||||
+ int offset = 0, err;
|
||||
+ u32 base;
|
||||
+
|
||||
+ mutex_lock(&bo->lock);
|
||||
+
|
||||
+ bo_va = lima_vm_bo_find(vm, bo);
|
||||
+ if (!bo_va) {
|
||||
+ err = -ENOENT;
|
||||
+ goto err_out0;
|
||||
+ }
|
||||
+
|
||||
+ mutex_lock(&vm->lock);
|
||||
+
|
||||
+ base = bo_va->node.start + (pageoff << PAGE_SHIFT);
|
||||
+ for_each_sg_dma_page(bo->base.sgt->sgl, &sg_iter,
|
||||
+ bo->base.sgt->nents, pageoff) {
|
||||
+ err = lima_vm_map_page(vm, sg_page_iter_dma_address(&sg_iter),
|
||||
+ base + offset);
|
||||
+ if (err)
|
||||
+ goto err_out1;
|
||||
+
|
||||
+ offset += PAGE_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&vm->lock);
|
||||
+
|
||||
+ mutex_unlock(&bo->lock);
|
||||
+ return 0;
|
||||
+
|
||||
+err_out1:
|
||||
+ if (offset)
|
||||
+ lima_vm_unmap_range(vm, base, base + offset - 1);
|
||||
+ mutex_unlock(&vm->lock);
|
||||
+err_out0:
|
||||
+ mutex_unlock(&bo->lock);
|
||||
+ return err;
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h
|
||||
index e0bdedcf14dd..22aeec77d84d 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_vm.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_vm.h
|
||||
@@ -58,5 +58,6 @@ static inline void lima_vm_put(struct lima_vm *vm)
|
||||
}
|
||||
|
||||
void lima_vm_print(struct lima_vm *vm);
|
||||
+int lima_vm_map_bo(struct lima_vm *vm, struct lima_bo *bo, int pageoff);
|
||||
|
||||
#endif
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,327 +0,0 @@
|
||||
From e2058aea7a06fbc3cf41e49173b973ff620d33e2 Mon Sep 17 00:00:00 2001
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
Date: Thu, 16 Jan 2020 21:11:55 +0800
|
||||
Subject: [PATCH 004/146] FROMGIT: drm/lima: support heap buffer creation
|
||||
|
||||
heap buffer is used as output of GP and input of PP for
|
||||
Mali Utgard GPU. Size of heap buffer depends on the task
|
||||
so is a runtime variable.
|
||||
|
||||
Previously we just create a large enough buffer as heap
|
||||
buffer. Now we add a heap buffer type to be able to
|
||||
increase the backup memory dynamically when GP fail due
|
||||
to lack of heap memory.
|
||||
|
||||
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-4-yuq825@gmail.com
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_drv.c | 6 +-
|
||||
drivers/gpu/drm/lima/lima_drv.h | 1 +
|
||||
drivers/gpu/drm/lima/lima_gem.c | 134 ++++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/lima/lima_gem.h | 4 +
|
||||
drivers/gpu/drm/lima/lima_vm.c | 4 +-
|
||||
include/uapi/drm/lima_drm.h | 9 ++-
|
||||
6 files changed, 147 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c
|
||||
index 124efe4fa97b..18f88aaef1a2 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_drv.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_drv.c
|
||||
@@ -15,10 +15,14 @@
|
||||
#include "lima_vm.h"
|
||||
|
||||
int lima_sched_timeout_ms;
|
||||
+uint lima_heap_init_nr_pages = 8;
|
||||
|
||||
MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms");
|
||||
module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444);
|
||||
|
||||
+MODULE_PARM_DESC(heap_init_nr_pages, "heap buffer init number of pages");
|
||||
+module_param_named(heap_init_nr_pages, lima_heap_init_nr_pages, uint, 0444);
|
||||
+
|
||||
static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
{
|
||||
struct drm_lima_get_param *args = data;
|
||||
@@ -68,7 +72,7 @@ static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_
|
||||
if (args->pad)
|
||||
return -EINVAL;
|
||||
|
||||
- if (args->flags)
|
||||
+ if (args->flags & ~(LIMA_BO_FLAG_HEAP))
|
||||
return -EINVAL;
|
||||
|
||||
if (args->size == 0)
|
||||
diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h
|
||||
index 69c7344715c9..f492ecc6a5d9 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_drv.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_drv.h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lima_ctx.h"
|
||||
|
||||
extern int lima_sched_timeout_ms;
|
||||
+extern uint lima_heap_init_nr_pages;
|
||||
|
||||
struct lima_vm;
|
||||
struct lima_bo;
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
|
||||
index d0059d8c97d8..5404e0d668db 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gem.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_gem.c
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sync_file.h>
|
||||
#include <linux/pagemap.h>
|
||||
+#include <linux/shmem_fs.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_syncobj.h>
|
||||
@@ -15,6 +17,83 @@
|
||||
#include "lima_gem.h"
|
||||
#include "lima_vm.h"
|
||||
|
||||
+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
|
||||
+{
|
||||
+ struct page **pages;
|
||||
+ struct address_space *mapping = bo->base.base.filp->f_mapping;
|
||||
+ struct device *dev = bo->base.base.dev->dev;
|
||||
+ size_t old_size = bo->heap_size;
|
||||
+ size_t new_size = bo->heap_size ? bo->heap_size * 2 :
|
||||
+ (lima_heap_init_nr_pages << PAGE_SHIFT);
|
||||
+ struct sg_table sgt;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ if (bo->heap_size >= bo->base.base.size)
|
||||
+ return -ENOSPC;
|
||||
+
|
||||
+ new_size = min(new_size, bo->base.base.size);
|
||||
+
|
||||
+ mutex_lock(&bo->base.pages_lock);
|
||||
+
|
||||
+ if (bo->base.pages) {
|
||||
+ pages = bo->base.pages;
|
||||
+ } else {
|
||||
+ pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
|
||||
+ sizeof(*pages), GFP_KERNEL | __GFP_ZERO);
|
||||
+ if (!pages) {
|
||||
+ mutex_unlock(&bo->base.pages_lock);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ bo->base.pages = pages;
|
||||
+ bo->base.pages_use_count = 1;
|
||||
+
|
||||
+ mapping_set_unevictable(mapping);
|
||||
+ }
|
||||
+
|
||||
+ for (i = old_size >> PAGE_SHIFT; i < new_size >> PAGE_SHIFT; i++) {
|
||||
+ struct page *page = shmem_read_mapping_page(mapping, i);
|
||||
+
|
||||
+ if (IS_ERR(page)) {
|
||||
+ mutex_unlock(&bo->base.pages_lock);
|
||||
+ return PTR_ERR(page);
|
||||
+ }
|
||||
+ pages[i] = page;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&bo->base.pages_lock);
|
||||
+
|
||||
+ ret = sg_alloc_table_from_pages(&sgt, pages, i, 0,
|
||||
+ new_size, GFP_KERNEL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (bo->base.sgt) {
|
||||
+ dma_unmap_sg(dev, bo->base.sgt->sgl,
|
||||
+ bo->base.sgt->nents, DMA_BIDIRECTIONAL);
|
||||
+ sg_free_table(bo->base.sgt);
|
||||
+ } else {
|
||||
+ bo->base.sgt = kmalloc(sizeof(*bo->base.sgt), GFP_KERNEL);
|
||||
+ if (!bo->base.sgt) {
|
||||
+ sg_free_table(&sgt);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dma_map_sg(dev, sgt.sgl, sgt.nents, DMA_BIDIRECTIONAL);
|
||||
+
|
||||
+ *bo->base.sgt = sgt;
|
||||
+
|
||||
+ if (vm) {
|
||||
+ ret = lima_vm_map_bo(vm, bo, old_size >> PAGE_SHIFT);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ bo->heap_size = new_size;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
u32 size, u32 flags, u32 *handle)
|
||||
{
|
||||
@@ -22,7 +101,8 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
gfp_t mask;
|
||||
struct drm_gem_shmem_object *shmem;
|
||||
struct drm_gem_object *obj;
|
||||
- struct sg_table *sgt;
|
||||
+ struct lima_bo *bo;
|
||||
+ bool is_heap = flags & LIMA_BO_FLAG_HEAP;
|
||||
|
||||
shmem = drm_gem_shmem_create(dev, size);
|
||||
if (IS_ERR(shmem))
|
||||
@@ -36,10 +116,18 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
mask |= __GFP_DMA32;
|
||||
mapping_set_gfp_mask(obj->filp->f_mapping, mask);
|
||||
|
||||
- sgt = drm_gem_shmem_get_pages_sgt(obj);
|
||||
- if (IS_ERR(sgt)) {
|
||||
- err = PTR_ERR(sgt);
|
||||
- goto out;
|
||||
+ if (is_heap) {
|
||||
+ bo = to_lima_bo(obj);
|
||||
+ err = lima_heap_alloc(bo, NULL);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+ } else {
|
||||
+ struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(obj);
|
||||
+
|
||||
+ if (IS_ERR(sgt)) {
|
||||
+ err = PTR_ERR(sgt);
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
err = drm_gem_handle_create(file, obj, handle);
|
||||
@@ -79,17 +167,47 @@ static void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *f
|
||||
lima_vm_bo_del(vm, bo);
|
||||
}
|
||||
|
||||
+static int lima_gem_pin(struct drm_gem_object *obj)
|
||||
+{
|
||||
+ struct lima_bo *bo = to_lima_bo(obj);
|
||||
+
|
||||
+ if (bo->heap_size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return drm_gem_shmem_pin(obj);
|
||||
+}
|
||||
+
|
||||
+static void *lima_gem_vmap(struct drm_gem_object *obj)
|
||||
+{
|
||||
+ struct lima_bo *bo = to_lima_bo(obj);
|
||||
+
|
||||
+ if (bo->heap_size)
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+
|
||||
+ return drm_gem_shmem_vmap(obj);
|
||||
+}
|
||||
+
|
||||
+static int lima_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ struct lima_bo *bo = to_lima_bo(obj);
|
||||
+
|
||||
+ if (bo->heap_size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return drm_gem_shmem_mmap(obj, vma);
|
||||
+}
|
||||
+
|
||||
static const struct drm_gem_object_funcs lima_gem_funcs = {
|
||||
.free = lima_gem_free_object,
|
||||
.open = lima_gem_object_open,
|
||||
.close = lima_gem_object_close,
|
||||
.print_info = drm_gem_shmem_print_info,
|
||||
- .pin = drm_gem_shmem_pin,
|
||||
+ .pin = lima_gem_pin,
|
||||
.unpin = drm_gem_shmem_unpin,
|
||||
.get_sg_table = drm_gem_shmem_get_sg_table,
|
||||
- .vmap = drm_gem_shmem_vmap,
|
||||
+ .vmap = lima_gem_vmap,
|
||||
.vunmap = drm_gem_shmem_vunmap,
|
||||
- .mmap = drm_gem_shmem_mmap,
|
||||
+ .mmap = lima_gem_mmap,
|
||||
};
|
||||
|
||||
struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size)
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h
|
||||
index 1800feb3e47f..ccea06142f4b 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gem.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_gem.h
|
||||
@@ -7,12 +7,15 @@
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
|
||||
struct lima_submit;
|
||||
+struct lima_vm;
|
||||
|
||||
struct lima_bo {
|
||||
struct drm_gem_shmem_object base;
|
||||
|
||||
struct mutex lock;
|
||||
struct list_head va;
|
||||
+
|
||||
+ size_t heap_size;
|
||||
};
|
||||
|
||||
static inline struct lima_bo *
|
||||
@@ -31,6 +34,7 @@ static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo)
|
||||
return bo->base.base.resv;
|
||||
}
|
||||
|
||||
+int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm);
|
||||
struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size);
|
||||
int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
u32 size, u32 flags, u32 *handle);
|
||||
diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c
|
||||
index 2e513841de6c..5b92fb82674a 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_vm.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_vm.c
|
||||
@@ -155,6 +155,7 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
|
||||
void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
|
||||
{
|
||||
struct lima_bo_va *bo_va;
|
||||
+ u32 size;
|
||||
|
||||
mutex_lock(&bo->lock);
|
||||
|
||||
@@ -166,8 +167,9 @@ void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo)
|
||||
|
||||
mutex_lock(&vm->lock);
|
||||
|
||||
+ size = bo->heap_size ? bo->heap_size : bo_va->node.size;
|
||||
lima_vm_unmap_range(vm, bo_va->node.start,
|
||||
- bo_va->node.start + bo_va->node.size - 1);
|
||||
+ bo_va->node.start + size - 1);
|
||||
|
||||
drm_mm_remove_node(&bo_va->node);
|
||||
|
||||
diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h
|
||||
index 95a00fb867e6..1ec58d652a5a 100644
|
||||
--- a/include/uapi/drm/lima_drm.h
|
||||
+++ b/include/uapi/drm/lima_drm.h
|
||||
@@ -32,12 +32,19 @@ struct drm_lima_get_param {
|
||||
__u64 value; /* out, parameter value */
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * heap buffer dynamically increase backup memory size when GP task fail
|
||||
+ * due to lack of heap memory. size field of heap buffer is an up bound of
|
||||
+ * the backup memory which can be set to a fairly large value.
|
||||
+ */
|
||||
+#define LIMA_BO_FLAG_HEAP (1 << 0)
|
||||
+
|
||||
/**
|
||||
* create a buffer for used by GPU
|
||||
*/
|
||||
struct drm_lima_gem_create {
|
||||
__u32 size; /* in, buffer size */
|
||||
- __u32 flags; /* in, currently no flags, must be zero */
|
||||
+ __u32 flags; /* in, buffer flags */
|
||||
__u32 handle; /* out, GEM buffer handle */
|
||||
__u32 pad; /* pad, must be zero */
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,247 +0,0 @@
|
||||
From 1205d670359f3cb93770adf7b23dc4e71de605fc Mon Sep 17 00:00:00 2001
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
Date: Thu, 16 Jan 2020 21:11:56 +0800
|
||||
Subject: [PATCH 005/146] FROMGIT: drm/lima: recover task by enlarging heap
|
||||
buffer
|
||||
|
||||
Increase heap buffer backup memory when GP receive PLBU
|
||||
out of memory interrupt, then resume the task.
|
||||
|
||||
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-5-yuq825@gmail.com
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_gp.c | 58 +++++++++++++++++++++++++++++--
|
||||
drivers/gpu/drm/lima/lima_mmu.c | 5 +++
|
||||
drivers/gpu/drm/lima/lima_mmu.h | 1 +
|
||||
drivers/gpu/drm/lima/lima_sched.c | 35 ++++++++++++++++---
|
||||
drivers/gpu/drm/lima/lima_sched.h | 6 ++++
|
||||
5 files changed, 98 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c
|
||||
index ccf49faedebf..52b210f9a605 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gp.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_gp.c
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "lima_device.h"
|
||||
#include "lima_gp.h"
|
||||
#include "lima_regs.h"
|
||||
+#include "lima_gem.h"
|
||||
+#include "lima_vm.h"
|
||||
|
||||
#define gp_write(reg, data) writel(data, ip->iomem + reg)
|
||||
#define gp_read(reg) readl(ip->iomem + reg)
|
||||
@@ -20,6 +22,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
|
||||
struct lima_ip *ip = data;
|
||||
struct lima_device *dev = ip->dev;
|
||||
struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
|
||||
+ struct lima_sched_task *task = pipe->current_task;
|
||||
u32 state = gp_read(LIMA_GP_INT_STAT);
|
||||
u32 status = gp_read(LIMA_GP_STATUS);
|
||||
bool done = false;
|
||||
@@ -29,8 +32,16 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (state & LIMA_GP_IRQ_MASK_ERROR) {
|
||||
- dev_err(dev->dev, "gp error irq state=%x status=%x\n",
|
||||
- state, status);
|
||||
+ if ((state & LIMA_GP_IRQ_MASK_ERROR) ==
|
||||
+ LIMA_GP_IRQ_PLBU_OUT_OF_MEM) {
|
||||
+ dev_dbg(dev->dev, "gp out of heap irq status=%x\n",
|
||||
+ status);
|
||||
+ } else {
|
||||
+ dev_err(dev->dev, "gp error irq state=%x status=%x\n",
|
||||
+ state, status);
|
||||
+ if (task)
|
||||
+ task->recoverable = false;
|
||||
+ }
|
||||
|
||||
/* mask all interrupts before hard reset */
|
||||
gp_write(LIMA_GP_INT_MASK, 0);
|
||||
@@ -43,6 +54,7 @@ static irqreturn_t lima_gp_irq_handler(int irq, void *data)
|
||||
bool active = status & (LIMA_GP_STATUS_VS_ACTIVE |
|
||||
LIMA_GP_STATUS_PLBU_ACTIVE);
|
||||
done = valid && !active;
|
||||
+ pipe->error = false;
|
||||
}
|
||||
|
||||
gp_write(LIMA_GP_INT_CLEAR, state);
|
||||
@@ -121,6 +133,22 @@ static void lima_gp_task_run(struct lima_sched_pipe *pipe,
|
||||
u32 cmd = 0;
|
||||
int i;
|
||||
|
||||
+ /* update real heap buffer size for GP */
|
||||
+ for (i = 0; i < task->num_bos; i++) {
|
||||
+ struct lima_bo *bo = task->bos[i];
|
||||
+
|
||||
+ if (bo->heap_size &&
|
||||
+ lima_vm_get_va(task->vm, bo) ==
|
||||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) {
|
||||
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
|
||||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] +
|
||||
+ bo->heap_size;
|
||||
+ task->recoverable = true;
|
||||
+ task->heap = bo;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (f[LIMA_GP_VSCL_START_ADDR >> 2] !=
|
||||
f[LIMA_GP_VSCL_END_ADDR >> 2])
|
||||
cmd |= LIMA_GP_CMD_START_VS;
|
||||
@@ -184,6 +212,31 @@ static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe)
|
||||
lima_sched_pipe_task_done(pipe);
|
||||
}
|
||||
|
||||
+static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
|
||||
+{
|
||||
+ struct lima_ip *ip = pipe->processor[0];
|
||||
+ struct lima_sched_task *task = pipe->current_task;
|
||||
+ struct drm_lima_gp_frame *frame = task->frame;
|
||||
+ u32 *f = frame->frame;
|
||||
+ size_t fail_size =
|
||||
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] -
|
||||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2];
|
||||
+
|
||||
+ if (fail_size == task->heap->heap_size) {
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = lima_heap_alloc(task->heap, task->vm);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
|
||||
+ gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
|
||||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size);
|
||||
+ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void lima_gp_print_version(struct lima_ip *ip)
|
||||
{
|
||||
u32 version, major, minor;
|
||||
@@ -270,6 +323,7 @@ int lima_gp_pipe_init(struct lima_device *dev)
|
||||
pipe->task_fini = lima_gp_task_fini;
|
||||
pipe->task_error = lima_gp_task_error;
|
||||
pipe->task_mmu_error = lima_gp_task_mmu_error;
|
||||
+ pipe->task_recover = lima_gp_task_recover;
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c
|
||||
index 97ec09dee572..f79d2af427e7 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_mmu.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_mmu.c
|
||||
@@ -99,6 +99,11 @@ void lima_mmu_fini(struct lima_ip *ip)
|
||||
|
||||
}
|
||||
|
||||
+void lima_mmu_flush_tlb(struct lima_ip *ip)
|
||||
+{
|
||||
+ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE);
|
||||
+}
|
||||
+
|
||||
void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm)
|
||||
{
|
||||
struct lima_device *dev = ip->dev;
|
||||
diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h
|
||||
index 8c78319bcc8e..4f8ccbebcba1 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_mmu.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_mmu.h
|
||||
@@ -10,6 +10,7 @@ struct lima_vm;
|
||||
int lima_mmu_init(struct lima_ip *ip);
|
||||
void lima_mmu_fini(struct lima_ip *ip);
|
||||
|
||||
+void lima_mmu_flush_tlb(struct lima_ip *ip);
|
||||
void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm);
|
||||
void lima_mmu_page_fault_resume(struct lima_ip *ip);
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c
|
||||
index b561dd05bd62..3886999b4533 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_sched.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_sched.c
|
||||
@@ -313,6 +313,26 @@ static const struct drm_sched_backend_ops lima_sched_ops = {
|
||||
.free_job = lima_sched_free_job,
|
||||
};
|
||||
|
||||
+static void lima_sched_recover_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct lima_sched_pipe *pipe =
|
||||
+ container_of(work, struct lima_sched_pipe, recover_work);
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < pipe->num_l2_cache; i++)
|
||||
+ lima_l2_cache_flush(pipe->l2_cache[i]);
|
||||
+
|
||||
+ if (pipe->bcast_mmu) {
|
||||
+ lima_mmu_flush_tlb(pipe->bcast_mmu);
|
||||
+ } else {
|
||||
+ for (i = 0; i < pipe->num_mmu; i++)
|
||||
+ lima_mmu_flush_tlb(pipe->mmu[i]);
|
||||
+ }
|
||||
+
|
||||
+ if (pipe->task_recover(pipe))
|
||||
+ drm_sched_fault(&pipe->base);
|
||||
+}
|
||||
+
|
||||
int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
|
||||
{
|
||||
unsigned int timeout = lima_sched_timeout_ms > 0 ?
|
||||
@@ -321,6 +341,8 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
|
||||
pipe->fence_context = dma_fence_context_alloc(1);
|
||||
spin_lock_init(&pipe->fence_lock);
|
||||
|
||||
+ INIT_WORK(&pipe->recover_work, lima_sched_recover_work);
|
||||
+
|
||||
return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0,
|
||||
msecs_to_jiffies(timeout), name);
|
||||
}
|
||||
@@ -332,11 +354,14 @@ void lima_sched_pipe_fini(struct lima_sched_pipe *pipe)
|
||||
|
||||
void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe)
|
||||
{
|
||||
- if (pipe->error)
|
||||
- drm_sched_fault(&pipe->base);
|
||||
- else {
|
||||
- struct lima_sched_task *task = pipe->current_task;
|
||||
-
|
||||
+ struct lima_sched_task *task = pipe->current_task;
|
||||
+
|
||||
+ if (pipe->error) {
|
||||
+ if (task && task->recoverable)
|
||||
+ schedule_work(&pipe->recover_work);
|
||||
+ else
|
||||
+ drm_sched_fault(&pipe->base);
|
||||
+ } else {
|
||||
pipe->task_fini(pipe);
|
||||
dma_fence_signal(task->fence);
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h
|
||||
index 1d814fecbcc0..d64393fb50a9 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_sched.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_sched.h
|
||||
@@ -20,6 +20,9 @@ struct lima_sched_task {
|
||||
struct lima_bo **bos;
|
||||
int num_bos;
|
||||
|
||||
+ bool recoverable;
|
||||
+ struct lima_bo *heap;
|
||||
+
|
||||
/* pipe fence */
|
||||
struct dma_fence *fence;
|
||||
};
|
||||
@@ -68,6 +71,9 @@ struct lima_sched_pipe {
|
||||
void (*task_fini)(struct lima_sched_pipe *pipe);
|
||||
void (*task_error)(struct lima_sched_pipe *pipe);
|
||||
void (*task_mmu_error)(struct lima_sched_pipe *pipe);
|
||||
+ int (*task_recover)(struct lima_sched_pipe *pipe);
|
||||
+
|
||||
+ struct work_struct recover_work;
|
||||
};
|
||||
|
||||
int lima_sched_task_init(struct lima_sched_task *task,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,48 +0,0 @@
|
||||
From b5da0390f260f6cfc633d496ee2ee1bc5233a877 Mon Sep 17 00:00:00 2001
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
Date: Thu, 16 Jan 2020 21:11:57 +0800
|
||||
Subject: [PATCH 006/146] FROMGIT: drm/lima: increase driver version to 1.1
|
||||
|
||||
Increase driver version for mesa driver to identify
|
||||
the support of new heap buffer interface.
|
||||
|
||||
Reviewed-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Tested-by: Andreas Baierl <ichgeh@imkreisrum.de>
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
Link: https://patchwork.freedesktop.org/patch/msgid/20200116131157.13346-6-yuq825@gmail.com
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_drv.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c
|
||||
index 18f88aaef1a2..2daac64d8955 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_drv.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_drv.c
|
||||
@@ -245,6 +245,12 @@ static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = {
|
||||
|
||||
DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops);
|
||||
|
||||
+/**
|
||||
+ * Changelog:
|
||||
+ *
|
||||
+ * - 1.1.0 - add heap buffer support
|
||||
+ */
|
||||
+
|
||||
static struct drm_driver lima_drm_driver = {
|
||||
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
|
||||
.open = lima_drm_driver_open,
|
||||
@@ -254,9 +260,9 @@ static struct drm_driver lima_drm_driver = {
|
||||
.fops = &lima_drm_driver_fops,
|
||||
.name = "lima",
|
||||
.desc = "lima DRM",
|
||||
- .date = "20190217",
|
||||
+ .date = "20191231",
|
||||
.major = 1,
|
||||
- .minor = 0,
|
||||
+ .minor = 1,
|
||||
.patchlevel = 0,
|
||||
|
||||
.gem_create_object = lima_gem_create_object,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,38 +0,0 @@
|
||||
From 532b7e7f35698a33640bdf36914d0e0acd8270ef Mon Sep 17 00:00:00 2001
|
||||
From: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
Date: Tue, 18 Feb 2020 22:09:52 +0000
|
||||
Subject: [PATCH 007/146] FROMGIT: drm/lima: fix recovering from PLBU out of
|
||||
memory
|
||||
|
||||
It looks like on PLBU_OUT_OF_MEM interrupt we need to resume from where we
|
||||
stopped, i.e. new PLBU heap start is old end. Also update end address
|
||||
in GP frame to grow heap on 2nd and subsequent out of memory interrupts.
|
||||
|
||||
Fixes: 2081e8dcf1ee ("drm/lima: recover task by enlarging heap buffer")
|
||||
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_gp.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c
|
||||
index 52b210f9a605..d8841c870d90 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gp.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_gp.c
|
||||
@@ -231,8 +231,13 @@ static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
|
||||
}
|
||||
|
||||
gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
|
||||
+ /* Resume from where we stopped, i.e. new start is old end */
|
||||
+ gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR,
|
||||
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
|
||||
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
|
||||
+ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size;
|
||||
gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
|
||||
- f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size);
|
||||
+ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
|
||||
gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,29 +0,0 @@
|
||||
From 8502dc53c6d999458b198a953d52339411524c9c Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 22 Jan 2020 11:04:49 +0100
|
||||
Subject: [PATCH 009/146] FROMGIT: dt-bindings: clk: meson: add the gxl
|
||||
internal dac gate
|
||||
|
||||
Add the gxl ACODEC clock id to the gxbb clock controller bindings
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
include/dt-bindings/clock/gxbb-clkc.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
|
||||
index db0763e96173..4073eb7a9da1 100644
|
||||
--- a/include/dt-bindings/clock/gxbb-clkc.h
|
||||
+++ b/include/dt-bindings/clock/gxbb-clkc.h
|
||||
@@ -146,5 +146,6 @@
|
||||
#define CLKID_CTS_VDAC 201
|
||||
#define CLKID_HDMI_TX 202
|
||||
#define CLKID_HDMI 205
|
||||
+#define CLKID_ACODEC 206
|
||||
|
||||
#endif /* __GXBB_CLKC_H */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,60 +0,0 @@
|
||||
From 17b823e4687b26ffe35a17e26128631afe49d0b2 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 22 Jan 2020 11:04:50 +0100
|
||||
Subject: [PATCH 010/146] FROMGIT: clk: meson: gxbb: add the gxl internal dac
|
||||
gate
|
||||
|
||||
Add the ACODEC clock gate to the gxl clk controller driver
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/gxbb.c | 3 +++
|
||||
drivers/clk/meson/gxbb.h | 2 +-
|
||||
2 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 1f9c056e684c..47916c4f1700 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -2613,6 +2613,7 @@ static MESON_GATE(gxbb_assist_misc, HHI_GCLK_MPEG0, 23);
|
||||
static MESON_GATE(gxbb_emmc_a, HHI_GCLK_MPEG0, 24);
|
||||
static MESON_GATE(gxbb_emmc_b, HHI_GCLK_MPEG0, 25);
|
||||
static MESON_GATE(gxbb_emmc_c, HHI_GCLK_MPEG0, 26);
|
||||
+static MESON_GATE(gxl_acodec, HHI_GCLK_MPEG0, 28);
|
||||
static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30);
|
||||
|
||||
static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2);
|
||||
@@ -3100,6 +3101,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
|
||||
[CLKID_HDMI_SEL] = &gxbb_hdmi_sel.hw,
|
||||
[CLKID_HDMI_DIV] = &gxbb_hdmi_div.hw,
|
||||
[CLKID_HDMI] = &gxbb_hdmi.hw,
|
||||
+ [CLKID_ACODEC] = &gxl_acodec.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
@@ -3491,6 +3493,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = {
|
||||
&gxl_hdmi_pll_od,
|
||||
&gxl_hdmi_pll_od2,
|
||||
&gxl_hdmi_pll_dco,
|
||||
+ &gxl_acodec,
|
||||
};
|
||||
|
||||
static const struct meson_eeclkc_data gxbb_clkc_data = {
|
||||
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
|
||||
index b53584fe66cf..1ee8cb7e2f5a 100644
|
||||
--- a/drivers/clk/meson/gxbb.h
|
||||
+++ b/drivers/clk/meson/gxbb.h
|
||||
@@ -188,7 +188,7 @@
|
||||
#define CLKID_HDMI_SEL 203
|
||||
#define CLKID_HDMI_DIV 204
|
||||
|
||||
-#define NR_CLKS 206
|
||||
+#define NR_CLKS 207
|
||||
|
||||
/* include the CLKIDs that have been made part of the DT binding */
|
||||
#include <dt-bindings/clock/gxbb-clkc.h>
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,56 +0,0 @@
|
||||
From d6a0ab839aaa36c6952e61e64500191126c74f40 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 22 Jan 2020 11:04:51 +0100
|
||||
Subject: [PATCH 011/146] FROMGIT: clk: meson: gxbb: set audio output clock
|
||||
hierarchy
|
||||
|
||||
The aiu devices peripheral clocks needs the aiu and aiu_glue clocks to
|
||||
operate. Reflect this hierarchy in the gxbb clock tree.
|
||||
|
||||
Fixes: 738f66d3211d ("clk: gxbb: add AmLogic GXBB clk controller driver")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/gxbb.c | 18 ++++++++++--------
|
||||
1 file changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 47916c4f1700..5fd6a574f8c3 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -2619,14 +2619,6 @@ static MESON_GATE(gxbb_spi, HHI_GCLK_MPEG0, 30);
|
||||
static MESON_GATE(gxbb_i2s_spdif, HHI_GCLK_MPEG1, 2);
|
||||
static MESON_GATE(gxbb_eth, HHI_GCLK_MPEG1, 3);
|
||||
static MESON_GATE(gxbb_demux, HHI_GCLK_MPEG1, 4);
|
||||
-static MESON_GATE(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6);
|
||||
-static MESON_GATE(gxbb_iec958, HHI_GCLK_MPEG1, 7);
|
||||
-static MESON_GATE(gxbb_i2s_out, HHI_GCLK_MPEG1, 8);
|
||||
-static MESON_GATE(gxbb_amclk, HHI_GCLK_MPEG1, 9);
|
||||
-static MESON_GATE(gxbb_aififo2, HHI_GCLK_MPEG1, 10);
|
||||
-static MESON_GATE(gxbb_mixer, HHI_GCLK_MPEG1, 11);
|
||||
-static MESON_GATE(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12);
|
||||
-static MESON_GATE(gxbb_adc, HHI_GCLK_MPEG1, 13);
|
||||
static MESON_GATE(gxbb_blkmv, HHI_GCLK_MPEG1, 14);
|
||||
static MESON_GATE(gxbb_aiu, HHI_GCLK_MPEG1, 15);
|
||||
static MESON_GATE(gxbb_uart1, HHI_GCLK_MPEG1, 16);
|
||||
@@ -2681,6 +2673,16 @@ static MESON_GATE(gxbb_ao_ahb_bus, HHI_GCLK_AO, 2);
|
||||
static MESON_GATE(gxbb_ao_iface, HHI_GCLK_AO, 3);
|
||||
static MESON_GATE(gxbb_ao_i2c, HHI_GCLK_AO, 4);
|
||||
|
||||
+/* AIU gates */
|
||||
+static MESON_PCLK(gxbb_aiu_glue, HHI_GCLK_MPEG1, 6, &gxbb_aiu.hw);
|
||||
+static MESON_PCLK(gxbb_iec958, HHI_GCLK_MPEG1, 7, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_i2s_out, HHI_GCLK_MPEG1, 8, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_amclk, HHI_GCLK_MPEG1, 9, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_aififo2, HHI_GCLK_MPEG1, 10, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_mixer, HHI_GCLK_MPEG1, 11, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_mixer_iface, HHI_GCLK_MPEG1, 12, &gxbb_aiu_glue.hw);
|
||||
+static MESON_PCLK(gxbb_adc, HHI_GCLK_MPEG1, 13, &gxbb_aiu_glue.hw);
|
||||
+
|
||||
/* Array of all clocks provided by this provider */
|
||||
|
||||
static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,42 +0,0 @@
|
||||
From 25132741a2bda8a016d2d0870fbeb244d0cdd545 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:51 +0100
|
||||
Subject: [PATCH 012/146] FROMGIT: ASoC: core: allow a dt node to provide
|
||||
several components
|
||||
|
||||
At the moment, querying the dai_name will stop of the first component
|
||||
matching the dt node. This does not allow a device (single dt node) to
|
||||
provide several ASoC components which could then be used through DT.
|
||||
|
||||
This change let the search go on if the xlate function of the component
|
||||
returns an error, giving the possibility to another component to match
|
||||
and return the dai_name.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/soc-core.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
|
||||
index 068d809c349a..03b87427faa7 100644
|
||||
--- a/sound/soc/soc-core.c
|
||||
+++ b/sound/soc/soc-core.c
|
||||
@@ -3102,6 +3102,14 @@ int snd_soc_get_dai_name(struct of_phandle_args *args,
|
||||
*dai_name = dai->driver->name;
|
||||
if (!*dai_name)
|
||||
*dai_name = pos->name;
|
||||
+ } else if (ret) {
|
||||
+ /*
|
||||
+ * if another error than ENOTSUPP is returned go on and
|
||||
+ * check if another component is provided with the same
|
||||
+ * node. This may happen if a device provides several
|
||||
+ * components
|
||||
+ */
|
||||
+ continue;
|
||||
}
|
||||
|
||||
break;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,73 +0,0 @@
|
||||
From 04c2c7ba6ac38afcca0dcee7b02dcad68912ec33 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 14 Feb 2020 14:47:04 +0100
|
||||
Subject: [PATCH 013/146] FROMGIT: ASoC: core: ensure component names are
|
||||
unique
|
||||
|
||||
Make sure each ASoC component is registered with a unique name.
|
||||
The component is derived from the device name. If a device registers more
|
||||
than one component, the component names will be the same.
|
||||
|
||||
This usually brings up a warning about the debugfs directory creation of
|
||||
the component since directory already exists.
|
||||
|
||||
In such case, start numbering the component of the device so the names
|
||||
don't collide anymore.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Link: https://lore.kernel.org/r/20200214134704.342501-1-jbrunet@baylibre.com
|
||||
Signed-off-by: Mark Brown <broonie@kernel.org>
|
||||
---
|
||||
sound/soc/soc-core.c | 29 ++++++++++++++++++++++++++++-
|
||||
1 file changed, 28 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
|
||||
index 03b87427faa7..6a58a8f6e3c4 100644
|
||||
--- a/sound/soc/soc-core.c
|
||||
+++ b/sound/soc/soc-core.c
|
||||
@@ -2446,6 +2446,33 @@ static int snd_soc_register_dais(struct snd_soc_component *component,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static char *snd_soc_component_unique_name(struct device *dev,
|
||||
+ struct snd_soc_component *component)
|
||||
+{
|
||||
+ struct snd_soc_component *pos;
|
||||
+ int count = 0;
|
||||
+ char *name, *unique;
|
||||
+
|
||||
+ name = fmt_single_name(dev, &component->id);
|
||||
+ if (!name)
|
||||
+ return name;
|
||||
+
|
||||
+ /* Count the number of components registred by the device */
|
||||
+ for_each_component(pos) {
|
||||
+ if (dev == pos->dev)
|
||||
+ count++;
|
||||
+ }
|
||||
+
|
||||
+ /* Keep naming as it is for the 1st component */
|
||||
+ if (!count)
|
||||
+ return name;
|
||||
+
|
||||
+ unique = devm_kasprintf(dev, GFP_KERNEL, "%s-%d", name, count);
|
||||
+ devm_kfree(dev, name);
|
||||
+
|
||||
+ return unique;
|
||||
+}
|
||||
+
|
||||
static int snd_soc_component_initialize(struct snd_soc_component *component,
|
||||
const struct snd_soc_component_driver *driver, struct device *dev)
|
||||
{
|
||||
@@ -2454,7 +2481,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
|
||||
INIT_LIST_HEAD(&component->card_list);
|
||||
mutex_init(&component->io_mutex);
|
||||
|
||||
- component->name = fmt_single_name(dev, &component->id);
|
||||
+ component->name = snd_soc_component_unique_name(dev, component);
|
||||
if (!component->name) {
|
||||
dev_err(dev, "ASoC: Failed to allocate name\n");
|
||||
return -ENOMEM;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,567 +0,0 @@
|
||||
From 9fcc658d50b1951e08ab53ca28adb607dbb46c18 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:52 +0100
|
||||
Subject: [PATCH 014/146] FROMGIT: ASoC: meson: g12a: extract codec-to-codec
|
||||
utils
|
||||
|
||||
The hdmi routing mechanism used on g12a hdmi is also used:
|
||||
* other Amlogic SoC types
|
||||
* for the internal DAC path
|
||||
|
||||
Each of these codec glues are slightly different but the idea
|
||||
behind it remains the same. This change extract some helper functions
|
||||
from the g12a-tohdmitx driver to make them available for other Amlogic
|
||||
codecs.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 4 +
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/g12a-tohdmitx.c | 219 ++++++-----------------------
|
||||
sound/soc/meson/meson-codec-glue.c | 149 ++++++++++++++++++++
|
||||
sound/soc/meson/meson-codec-glue.h | 32 +++++
|
||||
5 files changed, 230 insertions(+), 176 deletions(-)
|
||||
create mode 100644 sound/soc/meson/meson-codec-glue.c
|
||||
create mode 100644 sound/soc/meson/meson-codec-glue.h
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 2e3676147cea..ee6d53949d45 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -85,9 +85,13 @@ config SND_MESON_AXG_PDM
|
||||
Select Y or M to add support for PDM input embedded
|
||||
in the Amlogic AXG SoC family
|
||||
|
||||
+config SND_MESON_CODEC_GLUE
|
||||
+ tristate
|
||||
+
|
||||
config SND_MESON_G12A_TOHDMITX
|
||||
tristate "Amlogic G12A To HDMI TX Control Support"
|
||||
select REGMAP_MMIO
|
||||
+ select SND_MESON_CODEC_GLUE
|
||||
imply SND_SOC_HDMI_CODEC
|
||||
help
|
||||
Select Y or M to add support for HDMI audio on the g12a SoC
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 1a8b1470ed84..529a807b3f37 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o
|
||||
snd-soc-meson-axg-spdifin-objs := axg-spdifin.o
|
||||
snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
|
||||
snd-soc-meson-axg-pdm-objs := axg-pdm.o
|
||||
+snd-soc-meson-codec-glue-objs := meson-codec-glue.o
|
||||
snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
|
||||
|
||||
obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
|
||||
@@ -24,4 +25,5 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
|
||||
obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o
|
||||
obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
|
||||
obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
|
||||
+obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o
|
||||
obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
|
||||
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
|
||||
index 9cfbd343a00c..f8853f2fba08 100644
|
||||
--- a/sound/soc/meson/g12a-tohdmitx.c
|
||||
+++ b/sound/soc/meson/g12a-tohdmitx.c
|
||||
@@ -12,112 +12,51 @@
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
|
||||
+#include "meson-codec-glue.h"
|
||||
|
||||
#define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx"
|
||||
|
||||
#define TOHDMITX_CTRL0 0x0
|
||||
#define CTRL0_ENABLE_SHIFT 31
|
||||
-#define CTRL0_I2S_DAT_SEL GENMASK(13, 12)
|
||||
+#define CTRL0_I2S_DAT_SEL_SHIFT 12
|
||||
+#define CTRL0_I2S_DAT_SEL (0x3 << CTRL0_I2S_DAT_SEL_SHIFT)
|
||||
#define CTRL0_I2S_LRCLK_SEL GENMASK(9, 8)
|
||||
#define CTRL0_I2S_BLK_CAP_INV BIT(7)
|
||||
#define CTRL0_I2S_BCLK_O_INV BIT(6)
|
||||
#define CTRL0_I2S_BCLK_SEL GENMASK(5, 4)
|
||||
#define CTRL0_SPDIF_CLK_CAP_INV BIT(3)
|
||||
#define CTRL0_SPDIF_CLK_O_INV BIT(2)
|
||||
-#define CTRL0_SPDIF_SEL BIT(1)
|
||||
+#define CTRL0_SPDIF_SEL_SHIFT 1
|
||||
+#define CTRL0_SPDIF_SEL (0x1 << CTRL0_SPDIF_SEL_SHIFT)
|
||||
#define CTRL0_SPDIF_CLK_SEL BIT(0)
|
||||
|
||||
-struct g12a_tohdmitx_input {
|
||||
- struct snd_soc_pcm_stream params;
|
||||
- unsigned int fmt;
|
||||
-};
|
||||
-
|
||||
-static struct snd_soc_dapm_widget *
|
||||
-g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w)
|
||||
-{
|
||||
- struct snd_soc_dapm_path *p = NULL;
|
||||
- struct snd_soc_dapm_widget *in;
|
||||
-
|
||||
- snd_soc_dapm_widget_for_each_source_path(w, p) {
|
||||
- if (!p->connect)
|
||||
- continue;
|
||||
-
|
||||
- /* Check that we still are in the same component */
|
||||
- if (snd_soc_dapm_to_component(w->dapm) !=
|
||||
- snd_soc_dapm_to_component(p->source->dapm))
|
||||
- continue;
|
||||
-
|
||||
- if (p->source->id == snd_soc_dapm_dai_in)
|
||||
- return p->source;
|
||||
-
|
||||
- in = g12a_tohdmitx_get_input(p->source);
|
||||
- if (in)
|
||||
- return in;
|
||||
- }
|
||||
-
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
-static struct g12a_tohdmitx_input *
|
||||
-g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w)
|
||||
-{
|
||||
- struct snd_soc_dapm_widget *in =
|
||||
- g12a_tohdmitx_get_input(w);
|
||||
- struct snd_soc_dai *dai;
|
||||
-
|
||||
- if (WARN_ON(!in))
|
||||
- return NULL;
|
||||
-
|
||||
- dai = in->priv;
|
||||
-
|
||||
- return dai->playback_dma_data;
|
||||
-}
|
||||
-
|
||||
static const char * const g12a_tohdmitx_i2s_mux_texts[] = {
|
||||
"I2S A", "I2S B", "I2S C",
|
||||
};
|
||||
|
||||
-static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum,
|
||||
- g12a_tohdmitx_i2s_mux_texts);
|
||||
-
|
||||
-static int g12a_tohdmitx_get_input_val(struct snd_soc_component *component,
|
||||
- unsigned int mask)
|
||||
-{
|
||||
- unsigned int val;
|
||||
-
|
||||
- snd_soc_component_read(component, TOHDMITX_CTRL0, &val);
|
||||
- return (val & mask) >> __ffs(mask);
|
||||
-}
|
||||
-
|
||||
-static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol,
|
||||
- struct snd_ctl_elem_value *ucontrol)
|
||||
-{
|
||||
- struct snd_soc_component *component =
|
||||
- snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
-
|
||||
- ucontrol->value.enumerated.item[0] =
|
||||
- g12a_tohdmitx_get_input_val(component, CTRL0_I2S_DAT_SEL);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
- struct snd_ctl_elem_value *ucontrol)
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component =
|
||||
snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_dapm_kcontrol_dapm(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
- unsigned int mux = ucontrol->value.enumerated.item[0];
|
||||
- unsigned int val = g12a_tohdmitx_get_input_val(component,
|
||||
- CTRL0_I2S_DAT_SEL);
|
||||
+ unsigned int mux, changed;
|
||||
+
|
||||
+ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
|
||||
+ changed = snd_soc_component_test_bits(component, e->reg,
|
||||
+ CTRL0_I2S_DAT_SEL,
|
||||
+ FIELD_PREP(CTRL0_I2S_DAT_SEL,
|
||||
+ mux));
|
||||
+
|
||||
+ if (!changed)
|
||||
+ return 0;
|
||||
|
||||
/* Force disconnect of the mux while updating */
|
||||
- if (val != mux)
|
||||
- snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
|
||||
- snd_soc_component_update_bits(component, TOHDMITX_CTRL0,
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
CTRL0_I2S_DAT_SEL |
|
||||
CTRL0_I2S_LRCLK_SEL |
|
||||
CTRL0_I2S_BCLK_SEL,
|
||||
@@ -130,30 +69,19 @@ static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_i2s_mux_enum, TOHDMITX_CTRL0,
|
||||
+ CTRL0_I2S_DAT_SEL_SHIFT,
|
||||
+ g12a_tohdmitx_i2s_mux_texts);
|
||||
+
|
||||
static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux =
|
||||
SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum,
|
||||
- g12a_tohdmitx_i2s_mux_get_enum,
|
||||
+ snd_soc_dapm_get_enum_double,
|
||||
g12a_tohdmitx_i2s_mux_put_enum);
|
||||
|
||||
static const char * const g12a_tohdmitx_spdif_mux_texts[] = {
|
||||
"SPDIF A", "SPDIF B",
|
||||
};
|
||||
|
||||
-static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum,
|
||||
- g12a_tohdmitx_spdif_mux_texts);
|
||||
-
|
||||
-static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol,
|
||||
- struct snd_ctl_elem_value *ucontrol)
|
||||
-{
|
||||
- struct snd_soc_component *component =
|
||||
- snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
-
|
||||
- ucontrol->value.enumerated.item[0] =
|
||||
- g12a_tohdmitx_get_input_val(component, CTRL0_SPDIF_SEL);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@@ -162,13 +90,18 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_dapm_kcontrol_dapm(kcontrol);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
- unsigned int mux = ucontrol->value.enumerated.item[0];
|
||||
- unsigned int val = g12a_tohdmitx_get_input_val(component,
|
||||
- CTRL0_SPDIF_SEL);
|
||||
+ unsigned int mux, changed;
|
||||
+
|
||||
+ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
|
||||
+ changed = snd_soc_component_test_bits(component, TOHDMITX_CTRL0,
|
||||
+ CTRL0_SPDIF_SEL,
|
||||
+ FIELD_PREP(CTRL0_SPDIF_SEL, mux));
|
||||
+
|
||||
+ if (!changed)
|
||||
+ return 0;
|
||||
|
||||
/* Force disconnect of the mux while updating */
|
||||
- if (val != mux)
|
||||
- snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
|
||||
snd_soc_component_update_bits(component, TOHDMITX_CTRL0,
|
||||
CTRL0_SPDIF_SEL |
|
||||
@@ -181,9 +114,13 @@ static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static SOC_ENUM_SINGLE_DECL(g12a_tohdmitx_spdif_mux_enum, TOHDMITX_CTRL0,
|
||||
+ CTRL0_SPDIF_SEL_SHIFT,
|
||||
+ g12a_tohdmitx_spdif_mux_texts);
|
||||
+
|
||||
static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux =
|
||||
SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum,
|
||||
- g12a_tohdmitx_spdif_mux_get_enum,
|
||||
+ snd_soc_dapm_get_enum_double,
|
||||
g12a_tohdmitx_spdif_mux_put_enum);
|
||||
|
||||
static const struct snd_kcontrol_new g12a_tohdmitx_out_enable =
|
||||
@@ -201,83 +138,13 @@ static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = {
|
||||
&g12a_tohdmitx_out_enable),
|
||||
};
|
||||
|
||||
-static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai)
|
||||
-{
|
||||
- struct g12a_tohdmitx_input *data;
|
||||
-
|
||||
- data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
- if (!data)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- dai->playback_dma_data = data;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai)
|
||||
-{
|
||||
- kfree(dai->playback_dma_data);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream,
|
||||
- struct snd_pcm_hw_params *params,
|
||||
- struct snd_soc_dai *dai)
|
||||
-{
|
||||
- struct g12a_tohdmitx_input *data = dai->playback_dma_data;
|
||||
-
|
||||
- data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
|
||||
- data->params.rate_min = params_rate(params);
|
||||
- data->params.rate_max = params_rate(params);
|
||||
- data->params.formats = 1 << params_format(params);
|
||||
- data->params.channels_min = params_channels(params);
|
||||
- data->params.channels_max = params_channels(params);
|
||||
- data->params.sig_bits = dai->driver->playback.sig_bits;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-
|
||||
-static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai,
|
||||
- unsigned int fmt)
|
||||
-{
|
||||
- struct g12a_tohdmitx_input *data = dai->playback_dma_data;
|
||||
-
|
||||
- /* Save the source stream format for the downstream link */
|
||||
- data->fmt = fmt;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream,
|
||||
- struct snd_soc_dai *dai)
|
||||
-{
|
||||
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
- struct g12a_tohdmitx_input *in_data =
|
||||
- g12a_tohdmitx_get_input_data(dai->capture_widget);
|
||||
-
|
||||
- if (!in_data)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- if (WARN_ON(!rtd->dai_link->params)) {
|
||||
- dev_warn(dai->dev, "codec2codec link expected\n");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- /* Replace link params with the input params */
|
||||
- rtd->dai_link->params = &in_data->params;
|
||||
-
|
||||
- if (!in_data->fmt)
|
||||
- return 0;
|
||||
-
|
||||
- return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
|
||||
-}
|
||||
-
|
||||
static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = {
|
||||
- .hw_params = g12a_tohdmitx_input_hw_params,
|
||||
- .set_fmt = g12a_tohdmitx_input_set_fmt,
|
||||
+ .hw_params = meson_codec_glue_input_hw_params,
|
||||
+ .set_fmt = meson_codec_glue_input_set_fmt,
|
||||
};
|
||||
|
||||
static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
|
||||
- .startup = g12a_tohdmitx_output_startup,
|
||||
+ .startup = meson_codec_glue_output_startup,
|
||||
};
|
||||
|
||||
#define TOHDMITX_SPDIF_FORMATS \
|
||||
@@ -304,8 +171,8 @@ static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = {
|
||||
.id = (xid), \
|
||||
.playback = TOHDMITX_STREAM(xname, "Playback", xfmt, xchmax), \
|
||||
.ops = &g12a_tohdmitx_input_ops, \
|
||||
- .probe = g12a_tohdmitx_input_probe, \
|
||||
- .remove = g12a_tohdmitx_input_remove, \
|
||||
+ .probe = meson_codec_glue_input_dai_probe, \
|
||||
+ .remove = meson_codec_glue_input_dai_remove, \
|
||||
}
|
||||
|
||||
#define TOHDMITX_OUT(xname, xid, xfmt, xchmax) { \
|
||||
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
|
||||
new file mode 100644
|
||||
index 000000000000..97bbc967e176
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/meson-codec-glue.c
|
||||
@@ -0,0 +1,149 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// Copyright (c) 2019 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include "meson-codec-glue.h"
|
||||
+
|
||||
+static struct snd_soc_dapm_widget *
|
||||
+meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
|
||||
+{
|
||||
+ struct snd_soc_dapm_path *p = NULL;
|
||||
+ struct snd_soc_dapm_widget *in;
|
||||
+
|
||||
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
|
||||
+ if (!p->connect)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Check that we still are in the same component */
|
||||
+ if (snd_soc_dapm_to_component(w->dapm) !=
|
||||
+ snd_soc_dapm_to_component(p->source->dapm))
|
||||
+ continue;
|
||||
+
|
||||
+ if (p->source->id == snd_soc_dapm_dai_in)
|
||||
+ return p->source;
|
||||
+
|
||||
+ in = meson_codec_glue_get_input(p->source);
|
||||
+ if (in)
|
||||
+ return in;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
|
||||
+ struct meson_codec_glue_input *data)
|
||||
+{
|
||||
+ dai->playback_dma_data = data;
|
||||
+}
|
||||
+
|
||||
+struct meson_codec_glue_input *
|
||||
+meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ return dai->playback_dma_data;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
|
||||
+
|
||||
+static struct meson_codec_glue_input *
|
||||
+meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
|
||||
+{
|
||||
+ struct snd_soc_dapm_widget *in =
|
||||
+ meson_codec_glue_get_input(w);
|
||||
+ struct snd_soc_dai *dai;
|
||||
+
|
||||
+ if (WARN_ON(!in))
|
||||
+ return NULL;
|
||||
+
|
||||
+ dai = in->priv;
|
||||
+
|
||||
+ return meson_codec_glue_input_get_data(dai);
|
||||
+}
|
||||
+
|
||||
+int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data =
|
||||
+ meson_codec_glue_input_get_data(dai);
|
||||
+
|
||||
+ data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
|
||||
+ data->params.rate_min = params_rate(params);
|
||||
+ data->params.rate_max = params_rate(params);
|
||||
+ data->params.formats = 1 << params_format(params);
|
||||
+ data->params.channels_min = params_channels(params);
|
||||
+ data->params.channels_max = params_channels(params);
|
||||
+ data->params.sig_bits = dai->driver->playback.sig_bits;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
|
||||
+
|
||||
+int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
|
||||
+ unsigned int fmt)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data =
|
||||
+ meson_codec_glue_input_get_data(dai);
|
||||
+
|
||||
+ /* Save the source stream format for the downstream link */
|
||||
+ data->fmt = fmt;
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
|
||||
+
|
||||
+int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct meson_codec_glue_input *in_data =
|
||||
+ meson_codec_glue_output_get_input_data(dai->capture_widget);
|
||||
+
|
||||
+ if (!in_data)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (WARN_ON(!rtd->dai_link->params)) {
|
||||
+ dev_warn(dai->dev, "codec2codec link expected\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* Replace link params with the input params */
|
||||
+ rtd->dai_link->params = &in_data->params;
|
||||
+
|
||||
+ if (!in_data->fmt)
|
||||
+ return 0;
|
||||
+
|
||||
+ return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
|
||||
+
|
||||
+int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data;
|
||||
+
|
||||
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ meson_codec_glue_input_set_data(dai, data);
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
|
||||
+
|
||||
+int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data =
|
||||
+ meson_codec_glue_input_get_data(dai);
|
||||
+
|
||||
+ kfree(data);
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
|
||||
+
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+
|
||||
diff --git a/sound/soc/meson/meson-codec-glue.h b/sound/soc/meson/meson-codec-glue.h
|
||||
new file mode 100644
|
||||
index 000000000000..07f99446c0c6
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/meson-codec-glue.h
|
||||
@@ -0,0 +1,32 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0
|
||||
+ *
|
||||
+ * Copyright (c) 2018 Baylibre SAS.
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef _MESON_CODEC_GLUE_H
|
||||
+#define _MESON_CODEC_GLUE_H
|
||||
+
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+struct meson_codec_glue_input {
|
||||
+ struct snd_soc_pcm_stream params;
|
||||
+ unsigned int fmt;
|
||||
+};
|
||||
+
|
||||
+/* Input helpers */
|
||||
+struct meson_codec_glue_input *
|
||||
+meson_codec_glue_input_get_data(struct snd_soc_dai *dai);
|
||||
+int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai);
|
||||
+int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
|
||||
+ unsigned int fmt);
|
||||
+int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai);
|
||||
+int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai);
|
||||
+
|
||||
+/* Output helpers */
|
||||
+int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai);
|
||||
+
|
||||
+#endif /* _MESON_CODEC_GLUE_H */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,163 +0,0 @@
|
||||
From 659dbb6904d527ac9a6eebddb849e40f5753edc7 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:53 +0100
|
||||
Subject: [PATCH 015/146] FROMGIT: ASoC: meson: aiu: add audio output
|
||||
dt-bindings
|
||||
|
||||
Add the dt-bindings and documentation of the AIU audio controller.
|
||||
This component provides most of the audio outputs found on the Amlogic
|
||||
Gx SoC family.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../bindings/sound/amlogic,aiu.yaml | 111 ++++++++++++++++++
|
||||
include/dt-bindings/sound/meson-aiu.h | 18 +++
|
||||
2 files changed, 129 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
|
||||
create mode 100644 include/dt-bindings/sound/meson-aiu.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
|
||||
new file mode 100644
|
||||
index 000000000000..3ef7632dcb59
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/sound/amlogic,aiu.yaml
|
||||
@@ -0,0 +1,111 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/sound/amlogic,aiu.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Amlogic AIU audio output controller
|
||||
+
|
||||
+maintainers:
|
||||
+ - Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+properties:
|
||||
+ $nodename:
|
||||
+ pattern: "^audio-controller@.*"
|
||||
+
|
||||
+ "#sound-dai-cells":
|
||||
+ const: 2
|
||||
+
|
||||
+ compatible:
|
||||
+ items:
|
||||
+ - enum:
|
||||
+ - amlogic,aiu-gxbb
|
||||
+ - amlogic,aiu-gxl
|
||||
+ - const:
|
||||
+ amlogic,aiu
|
||||
+
|
||||
+ clocks:
|
||||
+ items:
|
||||
+ - description: AIU peripheral clock
|
||||
+ - description: I2S peripheral clock
|
||||
+ - description: I2S output clock
|
||||
+ - description: I2S master clock
|
||||
+ - description: I2S mixer clock
|
||||
+ - description: SPDIF peripheral clock
|
||||
+ - description: SPDIF output clock
|
||||
+ - description: SPDIF master clock
|
||||
+ - description: SPDIF master clock multiplexer
|
||||
+
|
||||
+ clock-names:
|
||||
+ items:
|
||||
+ - const: pclk
|
||||
+ - const: i2s_pclk
|
||||
+ - const: i2s_aoclk
|
||||
+ - const: i2s_mclk
|
||||
+ - const: i2s_mixer
|
||||
+ - const: spdif_pclk
|
||||
+ - const: spdif_aoclk
|
||||
+ - const: spdif_mclk
|
||||
+ - const: spdif_mclk_sel
|
||||
+
|
||||
+ interrupts:
|
||||
+ items:
|
||||
+ - description: I2S interrupt line
|
||||
+ - description: SPDIF interrupt line
|
||||
+
|
||||
+ interrupt-names:
|
||||
+ items:
|
||||
+ - const: i2s
|
||||
+ - const: spdif
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ resets:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+required:
|
||||
+ - "#sound-dai-cells"
|
||||
+ - compatible
|
||||
+ - clocks
|
||||
+ - clock-names
|
||||
+ - interrupts
|
||||
+ - interrupt-names
|
||||
+ - reg
|
||||
+ - resets
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ #include <dt-bindings/clock/gxbb-clkc.h>
|
||||
+ #include <dt-bindings/interrupt-controller/irq.h>
|
||||
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
+ #include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
|
||||
+
|
||||
+ aiu: audio-controller@5400 {
|
||||
+ compatible = "amlogic,aiu-gxl", "amlogic,aiu";
|
||||
+ #sound-dai-cells = <2>;
|
||||
+ reg = <0x0 0x5400 0x0 0x2ac>;
|
||||
+ interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>,
|
||||
+ <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
|
||||
+ interrupt-names = "i2s", "spdif";
|
||||
+ clocks = <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "pclk",
|
||||
+ "i2s_pclk",
|
||||
+ "i2s_aoclk",
|
||||
+ "i2s_mclk",
|
||||
+ "i2s_mixer",
|
||||
+ "spdif_pclk",
|
||||
+ "spdif_aoclk",
|
||||
+ "spdif_mclk",
|
||||
+ "spdif_mclk_sel";
|
||||
+ resets = <&reset RESET_AIU>;
|
||||
+ };
|
||||
+
|
||||
diff --git a/include/dt-bindings/sound/meson-aiu.h b/include/dt-bindings/sound/meson-aiu.h
|
||||
new file mode 100644
|
||||
index 000000000000..1051b8af298b
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/sound/meson-aiu.h
|
||||
@@ -0,0 +1,18 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+#ifndef __DT_MESON_AIU_H
|
||||
+#define __DT_MESON_AIU_H
|
||||
+
|
||||
+#define AIU_CPU 0
|
||||
+#define AIU_HDMI 1
|
||||
+#define AIU_ACODEC 2
|
||||
+
|
||||
+#define CPU_I2S_FIFO 0
|
||||
+#define CPU_SPDIF_FIFO 1
|
||||
+#define CPU_I2S_ENCODER 2
|
||||
+#define CPU_SPDIF_ENCODER 3
|
||||
+
|
||||
+#define CTRL_I2S 0
|
||||
+#define CTRL_PCM 1
|
||||
+#define CTRL_OUT 2
|
||||
+
|
||||
+#endif /* __DT_MESON_AIU_H */
|
||||
--
|
||||
2.17.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,281 +0,0 @@
|
||||
From b31b05925df0a3fd7041e3263f033a4621cd0d55 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:55 +0100
|
||||
Subject: [PATCH 017/146] FROMGIT: ASoC: meson: aiu: add hdmi codec control
|
||||
support
|
||||
|
||||
Add the codec to codec component which handles the routing between
|
||||
the audio producers (PCM and I2S) and the synopsys hdmi controller
|
||||
on the amlogic GX SoC family
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 2 +
|
||||
sound/soc/meson/Makefile | 1 +
|
||||
sound/soc/meson/aiu-codec-ctrl.c | 152 +++++++++++++++++++++++++++++++
|
||||
sound/soc/meson/aiu.c | 34 ++++++-
|
||||
sound/soc/meson/aiu.h | 8 ++
|
||||
5 files changed, 196 insertions(+), 1 deletion(-)
|
||||
create mode 100644 sound/soc/meson/aiu-codec-ctrl.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index ca269dedfc7f..19de97ae4ce9 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -4,7 +4,9 @@ menu "ASoC support for Amlogic platforms"
|
||||
|
||||
config SND_MESON_AIU
|
||||
tristate "Amlogic AIU"
|
||||
+ select SND_MESON_CODEC_GLUE
|
||||
select SND_PCM_IEC958
|
||||
+ imply SND_SOC_HDMI_CODEC if DRM_MESON_DW_HDMI
|
||||
help
|
||||
Select Y or M to add support for the Audio output subsystem found
|
||||
in the Amlogic GX SoC family
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index a7b79d717288..3b21f648e322 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
|
||||
snd-soc-meson-aiu-objs := aiu.o
|
||||
+snd-soc-meson-aiu-objs += aiu-codec-ctrl.o
|
||||
snd-soc-meson-aiu-objs += aiu-encoder-i2s.o
|
||||
snd-soc-meson-aiu-objs += aiu-encoder-spdif.o
|
||||
snd-soc-meson-aiu-objs += aiu-fifo.o
|
||||
diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c
|
||||
new file mode 100644
|
||||
index 000000000000..8646a953e3b3
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-codec-ctrl.c
|
||||
@@ -0,0 +1,152 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// Copyright (c) 2020 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
+#include "aiu.h"
|
||||
+#include "meson-codec-glue.h"
|
||||
+
|
||||
+#define CTRL_CLK_SEL GENMASK(1, 0)
|
||||
+#define CTRL_DATA_SEL_SHIFT 4
|
||||
+#define CTRL_DATA_SEL (0x3 << CTRL_DATA_SEL_SHIFT)
|
||||
+
|
||||
+static const char * const aiu_codec_ctrl_mux_texts[] = {
|
||||
+ "DISABLED", "PCM", "I2S",
|
||||
+};
|
||||
+
|
||||
+static int aiu_codec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ struct snd_soc_component *component =
|
||||
+ snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
+ struct snd_soc_dapm_context *dapm =
|
||||
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
|
||||
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
+ unsigned int mux, changed;
|
||||
+
|
||||
+ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
|
||||
+ changed = snd_soc_component_test_bits(component, e->reg,
|
||||
+ CTRL_DATA_SEL,
|
||||
+ FIELD_PREP(CTRL_DATA_SEL, mux));
|
||||
+
|
||||
+ if (!changed)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Force disconnect of the mux while updating */
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
+
|
||||
+ /* Reset the source first */
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
+ CTRL_CLK_SEL |
|
||||
+ CTRL_DATA_SEL,
|
||||
+ FIELD_PREP(CTRL_CLK_SEL, 0) |
|
||||
+ FIELD_PREP(CTRL_DATA_SEL, 0));
|
||||
+
|
||||
+ /* Set the appropriate source */
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
+ CTRL_CLK_SEL |
|
||||
+ CTRL_DATA_SEL,
|
||||
+ FIELD_PREP(CTRL_CLK_SEL, mux) |
|
||||
+ FIELD_PREP(CTRL_DATA_SEL, mux));
|
||||
+
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static SOC_ENUM_SINGLE_DECL(aiu_hdmi_ctrl_mux_enum, AIU_HDMI_CLK_DATA_CTRL,
|
||||
+ CTRL_DATA_SEL_SHIFT,
|
||||
+ aiu_codec_ctrl_mux_texts);
|
||||
+
|
||||
+static const struct snd_kcontrol_new aiu_hdmi_ctrl_mux =
|
||||
+ SOC_DAPM_ENUM_EXT("HDMI Source", aiu_hdmi_ctrl_mux_enum,
|
||||
+ snd_soc_dapm_get_enum_double,
|
||||
+ aiu_codec_ctrl_mux_put_enum);
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget aiu_hdmi_ctrl_widgets[] = {
|
||||
+ SND_SOC_DAPM_MUX("HDMI CTRL SRC", SND_SOC_NOPM, 0, 0,
|
||||
+ &aiu_hdmi_ctrl_mux),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dai_ops aiu_codec_ctrl_input_ops = {
|
||||
+ .hw_params = meson_codec_glue_input_hw_params,
|
||||
+ .set_fmt = meson_codec_glue_input_set_fmt,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dai_ops aiu_codec_ctrl_output_ops = {
|
||||
+ .startup = meson_codec_glue_output_startup,
|
||||
+};
|
||||
+
|
||||
+#define AIU_CODEC_CTRL_FORMATS \
|
||||
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE)
|
||||
+
|
||||
+#define AIU_CODEC_CTRL_STREAM(xname, xsuffix) \
|
||||
+{ \
|
||||
+ .stream_name = xname " " xsuffix, \
|
||||
+ .channels_min = 1, \
|
||||
+ .channels_max = 8, \
|
||||
+ .rate_min = 5512, \
|
||||
+ .rate_max = 192000, \
|
||||
+ .formats = AIU_CODEC_CTRL_FORMATS, \
|
||||
+}
|
||||
+
|
||||
+#define AIU_CODEC_CTRL_INPUT(xname) { \
|
||||
+ .name = "CODEC CTRL " xname, \
|
||||
+ .playback = AIU_CODEC_CTRL_STREAM(xname, "Playback"), \
|
||||
+ .ops = &aiu_codec_ctrl_input_ops, \
|
||||
+ .probe = meson_codec_glue_input_dai_probe, \
|
||||
+ .remove = meson_codec_glue_input_dai_remove, \
|
||||
+}
|
||||
+
|
||||
+#define AIU_CODEC_CTRL_OUTPUT(xname) { \
|
||||
+ .name = "CODEC CTRL " xname, \
|
||||
+ .capture = AIU_CODEC_CTRL_STREAM(xname, "Capture"), \
|
||||
+ .ops = &aiu_codec_ctrl_output_ops, \
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_dai_driver aiu_hdmi_ctrl_dai_drv[] = {
|
||||
+ [CTRL_I2S] = AIU_CODEC_CTRL_INPUT("HDMI I2S IN"),
|
||||
+ [CTRL_PCM] = AIU_CODEC_CTRL_INPUT("HDMI PCM IN"),
|
||||
+ [CTRL_OUT] = AIU_CODEC_CTRL_OUTPUT("HDMI OUT"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route aiu_hdmi_ctrl_routes[] = {
|
||||
+ { "HDMI CTRL SRC", "I2S", "HDMI I2S IN Playback" },
|
||||
+ { "HDMI CTRL SRC", "PCM", "HDMI PCM IN Playback" },
|
||||
+ { "HDMI OUT Capture", NULL, "HDMI CTRL SRC" },
|
||||
+};
|
||||
+
|
||||
+static int aiu_hdmi_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
+ struct of_phandle_args *args,
|
||||
+ const char **dai_name)
|
||||
+{
|
||||
+ return aiu_of_xlate_dai_name(component, args, dai_name, AIU_HDMI);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = {
|
||||
+ .name = "AIU HDMI Codec Control",
|
||||
+ .dapm_widgets = aiu_hdmi_ctrl_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(aiu_hdmi_ctrl_widgets),
|
||||
+ .dapm_routes = aiu_hdmi_ctrl_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(aiu_hdmi_ctrl_routes),
|
||||
+ .of_xlate_dai_name = aiu_hdmi_of_xlate_dai_name,
|
||||
+ .endianness = 1,
|
||||
+ .non_legacy_dai_naming = 1,
|
||||
+};
|
||||
+
|
||||
+int aiu_hdmi_ctrl_register_component(struct device *dev)
|
||||
+{
|
||||
+ return aiu_add_component(dev, &aiu_hdmi_ctrl_component,
|
||||
+ aiu_hdmi_ctrl_dai_drv,
|
||||
+ ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv),
|
||||
+ "hdmi");
|
||||
+}
|
||||
+
|
||||
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
|
||||
index a62aced9b687..b765dfb70726 100644
|
||||
--- a/sound/soc/meson/aiu.c
|
||||
+++ b/sound/soc/meson/aiu.c
|
||||
@@ -71,6 +71,26 @@ int aiu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int aiu_add_component(struct device *dev,
|
||||
+ const struct snd_soc_component_driver *component_driver,
|
||||
+ struct snd_soc_dai_driver *dai_drv,
|
||||
+ int num_dai,
|
||||
+ const char *debugfs_prefix)
|
||||
+{
|
||||
+ struct snd_soc_component *component;
|
||||
+
|
||||
+ component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
|
||||
+ if (!component)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+#ifdef CONFIG_DEBUG_FS
|
||||
+ component->debugfs_prefix = debugfs_prefix;
|
||||
+#endif
|
||||
+
|
||||
+ return snd_soc_add_component(dev, component, component_driver,
|
||||
+ dai_drv, num_dai);
|
||||
+}
|
||||
+
|
||||
static int aiu_cpu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name)
|
||||
@@ -313,9 +333,21 @@ static int aiu_probe(struct platform_device *pdev)
|
||||
ret = snd_soc_register_component(dev, &aiu_cpu_component,
|
||||
aiu_cpu_dai_drv,
|
||||
ARRAY_SIZE(aiu_cpu_dai_drv));
|
||||
- if (ret)
|
||||
+ if (ret) {
|
||||
dev_err(dev, "Failed to register cpu component\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
+ /* Register the hdmi codec control component */
|
||||
+ ret = aiu_hdmi_ctrl_register_component(dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to register hdmi control component\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+err:
|
||||
+ snd_soc_unregister_component(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
|
||||
index a3488027b9d5..9242ab1ab64b 100644
|
||||
--- a/sound/soc/meson/aiu.h
|
||||
+++ b/sound/soc/meson/aiu.h
|
||||
@@ -45,6 +45,14 @@ int aiu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
const char **dai_name,
|
||||
unsigned int component_id);
|
||||
|
||||
+int aiu_add_component(struct device *dev,
|
||||
+ const struct snd_soc_component_driver *component_driver,
|
||||
+ struct snd_soc_dai_driver *dai_drv,
|
||||
+ int num_dai,
|
||||
+ const char *debugfs_prefix);
|
||||
+
|
||||
+int aiu_hdmi_ctrl_register_component(struct device *dev);
|
||||
+
|
||||
int aiu_fifo_i2s_dai_probe(struct snd_soc_dai *dai);
|
||||
int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,279 +0,0 @@
|
||||
From 5104eb54c2ea560b6734c46c6185b71f6fd77cd2 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:56 +0100
|
||||
Subject: [PATCH 018/146] FROMGIT: ASoC: meson: aiu: add internal dac codec
|
||||
control support
|
||||
|
||||
Add the codec to codec component which handles the routing between
|
||||
the audio producers and the internal audio DAC found on the amlogic GXL
|
||||
SoC family
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Makefile | 1 +
|
||||
sound/soc/meson/aiu-acodec-ctrl.c | 205 ++++++++++++++++++++++++++++++
|
||||
sound/soc/meson/aiu.c | 10 ++
|
||||
sound/soc/meson/aiu.h | 1 +
|
||||
4 files changed, 217 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-acodec-ctrl.c
|
||||
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 3b21f648e322..80f9113701b3 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
|
||||
snd-soc-meson-aiu-objs := aiu.o
|
||||
+snd-soc-meson-aiu-objs += aiu-acodec-ctrl.o
|
||||
snd-soc-meson-aiu-objs += aiu-codec-ctrl.o
|
||||
snd-soc-meson-aiu-objs += aiu-encoder-i2s.o
|
||||
snd-soc-meson-aiu-objs += aiu-encoder-spdif.o
|
||||
diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
new file mode 100644
|
||||
index 000000000000..12d8a4d351a1
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
@@ -0,0 +1,205 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// Copyright (c) 2020 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
+#include "aiu.h"
|
||||
+#include "meson-codec-glue.h"
|
||||
+
|
||||
+#define CTRL_DIN_EN 15
|
||||
+#define CTRL_CLK_INV BIT(14)
|
||||
+#define CTRL_LRCLK_INV BIT(13)
|
||||
+#define CTRL_I2S_IN_BCLK_SRC BIT(11)
|
||||
+#define CTRL_DIN_LRCLK_SRC_SHIFT 6
|
||||
+#define CTRL_DIN_LRCLK_SRC (0x3 << CTRL_DIN_LRCLK_SRC_SHIFT)
|
||||
+#define CTRL_BCLK_MCLK_SRC GENMASK(5, 4)
|
||||
+#define CTRL_DIN_SKEW GENMASK(3, 2)
|
||||
+#define CTRL_I2S_OUT_LANE_SRC 0
|
||||
+
|
||||
+#define AIU_ACODEC_OUT_CHMAX 2
|
||||
+
|
||||
+static const char * const aiu_acodec_ctrl_mux_texts[] = {
|
||||
+ "DISABLED", "I2S", "PCM",
|
||||
+};
|
||||
+
|
||||
+static int aiu_acodec_ctrl_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ struct snd_soc_component *component =
|
||||
+ snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
+ struct snd_soc_dapm_context *dapm =
|
||||
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
|
||||
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
+ unsigned int mux, changed;
|
||||
+
|
||||
+ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
|
||||
+ changed = snd_soc_component_test_bits(component, e->reg,
|
||||
+ CTRL_DIN_LRCLK_SRC,
|
||||
+ FIELD_PREP(CTRL_DIN_LRCLK_SRC,
|
||||
+ mux));
|
||||
+
|
||||
+ if (!changed)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Force disconnect of the mux while updating */
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
+ CTRL_DIN_LRCLK_SRC |
|
||||
+ CTRL_BCLK_MCLK_SRC,
|
||||
+ FIELD_PREP(CTRL_DIN_LRCLK_SRC, mux) |
|
||||
+ FIELD_PREP(CTRL_BCLK_MCLK_SRC, mux));
|
||||
+
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static SOC_ENUM_SINGLE_DECL(aiu_acodec_ctrl_mux_enum, AIU_ACODEC_CTRL,
|
||||
+ CTRL_DIN_LRCLK_SRC_SHIFT,
|
||||
+ aiu_acodec_ctrl_mux_texts);
|
||||
+
|
||||
+static const struct snd_kcontrol_new aiu_acodec_ctrl_mux =
|
||||
+ SOC_DAPM_ENUM_EXT("ACodec Source", aiu_acodec_ctrl_mux_enum,
|
||||
+ snd_soc_dapm_get_enum_double,
|
||||
+ aiu_acodec_ctrl_mux_put_enum);
|
||||
+
|
||||
+static const struct snd_kcontrol_new aiu_acodec_ctrl_out_enable =
|
||||
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", AIU_ACODEC_CTRL,
|
||||
+ CTRL_DIN_EN, 1, 0);
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget aiu_acodec_ctrl_widgets[] = {
|
||||
+ SND_SOC_DAPM_MUX("ACODEC SRC", SND_SOC_NOPM, 0, 0,
|
||||
+ &aiu_acodec_ctrl_mux),
|
||||
+ SND_SOC_DAPM_SWITCH("ACODEC OUT EN", SND_SOC_NOPM, 0, 0,
|
||||
+ &aiu_acodec_ctrl_out_enable),
|
||||
+};
|
||||
+
|
||||
+static int aiu_acodec_ctrl_input_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = meson_codec_glue_input_hw_params(substream, params, dai);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* The glue will provide 1 lane out of the 4 to the output */
|
||||
+ data = meson_codec_glue_input_get_data(dai);
|
||||
+ data->params.channels_min = min_t(unsigned int, AIU_ACODEC_OUT_CHMAX,
|
||||
+ data->params.channels_min);
|
||||
+ data->params.channels_max = min_t(unsigned int, AIU_ACODEC_OUT_CHMAX,
|
||||
+ data->params.channels_max);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops aiu_acodec_ctrl_input_ops = {
|
||||
+ .hw_params = aiu_acodec_ctrl_input_hw_params,
|
||||
+ .set_fmt = meson_codec_glue_input_set_fmt,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = {
|
||||
+ .startup = meson_codec_glue_output_startup,
|
||||
+};
|
||||
+
|
||||
+#define AIU_ACODEC_CTRL_FORMATS \
|
||||
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
|
||||
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE)
|
||||
+
|
||||
+#define AIU_ACODEC_STREAM(xname, xsuffix, xchmax) \
|
||||
+{ \
|
||||
+ .stream_name = xname " " xsuffix, \
|
||||
+ .channels_min = 1, \
|
||||
+ .channels_max = (xchmax), \
|
||||
+ .rate_min = 5512, \
|
||||
+ .rate_max = 192000, \
|
||||
+ .formats = AIU_ACODEC_CTRL_FORMATS, \
|
||||
+}
|
||||
+
|
||||
+#define AIU_ACODEC_INPUT(xname) { \
|
||||
+ .name = "ACODEC CTRL " xname, \
|
||||
+ .name = xname, \
|
||||
+ .playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \
|
||||
+ .ops = &aiu_acodec_ctrl_input_ops, \
|
||||
+ .probe = meson_codec_glue_input_dai_probe, \
|
||||
+ .remove = meson_codec_glue_input_dai_remove, \
|
||||
+}
|
||||
+
|
||||
+#define AIU_ACODEC_OUTPUT(xname) { \
|
||||
+ .name = "ACODEC CTRL " xname, \
|
||||
+ .capture = AIU_ACODEC_STREAM(xname, "Capture", AIU_ACODEC_OUT_CHMAX), \
|
||||
+ .ops = &aiu_acodec_ctrl_output_ops, \
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_dai_driver aiu_acodec_ctrl_dai_drv[] = {
|
||||
+ [CTRL_I2S] = AIU_ACODEC_INPUT("ACODEC I2S IN"),
|
||||
+ [CTRL_PCM] = AIU_ACODEC_INPUT("ACODEC PCM IN"),
|
||||
+ [CTRL_OUT] = AIU_ACODEC_OUTPUT("ACODEC OUT"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route aiu_acodec_ctrl_routes[] = {
|
||||
+ { "ACODEC SRC", "I2S", "ACODEC I2S IN Playback" },
|
||||
+ { "ACODEC SRC", "PCM", "ACODEC PCM IN Playback" },
|
||||
+ { "ACODEC OUT EN", "Switch", "ACODEC SRC" },
|
||||
+ { "ACODEC OUT Capture", NULL, "ACODEC OUT EN" },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_kcontrol_new aiu_acodec_ctrl_controls[] = {
|
||||
+ SOC_SINGLE("ACODEC I2S Lane Select", AIU_ACODEC_CTRL,
|
||||
+ CTRL_I2S_OUT_LANE_SRC, 3, 0),
|
||||
+};
|
||||
+
|
||||
+static int aiu_acodec_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
+ struct of_phandle_args *args,
|
||||
+ const char **dai_name)
|
||||
+{
|
||||
+ return aiu_of_xlate_dai_name(component, args, dai_name, AIU_ACODEC);
|
||||
+}
|
||||
+
|
||||
+static int aiu_acodec_ctrl_component_probe(struct snd_soc_component *component)
|
||||
+{
|
||||
+ /*
|
||||
+ * NOTE: Din Skew setting
|
||||
+ * According to the documentation, the following update adds one delay
|
||||
+ * to the din line. Without this, the output saturates. This happens
|
||||
+ * regardless of the link format (i2s or left_j) so it is not clear what
|
||||
+ * it actually does but it seems to be required
|
||||
+ */
|
||||
+ snd_soc_component_update_bits(component, AIU_ACODEC_CTRL,
|
||||
+ CTRL_DIN_SKEW,
|
||||
+ FIELD_PREP(CTRL_DIN_SKEW, 2));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_acodec_ctrl_component = {
|
||||
+ .name = "AIU Internal DAC Codec Control",
|
||||
+ .probe = aiu_acodec_ctrl_component_probe,
|
||||
+ .controls = aiu_acodec_ctrl_controls,
|
||||
+ .num_controls = ARRAY_SIZE(aiu_acodec_ctrl_controls),
|
||||
+ .dapm_widgets = aiu_acodec_ctrl_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(aiu_acodec_ctrl_widgets),
|
||||
+ .dapm_routes = aiu_acodec_ctrl_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(aiu_acodec_ctrl_routes),
|
||||
+ .of_xlate_dai_name = aiu_acodec_of_xlate_dai_name,
|
||||
+ .endianness = 1,
|
||||
+ .non_legacy_dai_naming = 1,
|
||||
+};
|
||||
+
|
||||
+int aiu_acodec_ctrl_register_component(struct device *dev)
|
||||
+{
|
||||
+ return aiu_add_component(dev, &aiu_acodec_ctrl_component,
|
||||
+ aiu_acodec_ctrl_dai_drv,
|
||||
+ ARRAY_SIZE(aiu_acodec_ctrl_dai_drv),
|
||||
+ "acodec");
|
||||
+}
|
||||
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
|
||||
index b765dfb70726..5c4845a23a34 100644
|
||||
--- a/sound/soc/meson/aiu.c
|
||||
+++ b/sound/soc/meson/aiu.c
|
||||
@@ -345,6 +345,16 @@ static int aiu_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
+ /* Register the internal dac control component on gxl */
|
||||
+ if (of_device_is_compatible(dev->of_node, "amlogic,aiu-gxl")) {
|
||||
+ ret = aiu_acodec_ctrl_register_component(dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev,
|
||||
+ "Failed to register acodec control component\n");
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
err:
|
||||
snd_soc_unregister_component(dev);
|
||||
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
|
||||
index 9242ab1ab64b..a65a576e3400 100644
|
||||
--- a/sound/soc/meson/aiu.h
|
||||
+++ b/sound/soc/meson/aiu.h
|
||||
@@ -52,6 +52,7 @@ int aiu_add_component(struct device *dev,
|
||||
const char *debugfs_prefix);
|
||||
|
||||
int aiu_hdmi_ctrl_register_component(struct device *dev);
|
||||
+int aiu_acodec_ctrl_register_component(struct device *dev);
|
||||
|
||||
int aiu_fifo_i2s_dai_probe(struct snd_soc_dai *dai);
|
||||
int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai);
|
||||
--
|
||||
2.17.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,138 +0,0 @@
|
||||
From d23068202d53370a8d4aa52219584943d8a526c8 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:58 +0100
|
||||
Subject: [PATCH 020/146] FROMGIT: ASoC: meson: gx: add sound card dt-binding
|
||||
documentation
|
||||
|
||||
Add the dt-binding documentation of sound card supporting the amlogic
|
||||
GX SoC family
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../bindings/sound/amlogic,gx-sound-card.yaml | 113 ++++++++++++++++++
|
||||
1 file changed, 113 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
|
||||
new file mode 100644
|
||||
index 000000000000..fb374c659be1
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
|
||||
@@ -0,0 +1,113 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/sound/amlogic,gx-sound-card.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Amlogic GX sound card
|
||||
+
|
||||
+maintainers:
|
||||
+ - Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ items:
|
||||
+ - const: amlogic,gx-sound-card
|
||||
+
|
||||
+ audio-aux-devs:
|
||||
+ $ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
+ description: list of auxiliary devices
|
||||
+
|
||||
+ audio-routing:
|
||||
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
+ minItems: 2
|
||||
+ description: |-
|
||||
+ A list of the connections between audio components. Each entry is a
|
||||
+ pair of strings, the first being the connection's sink, the second
|
||||
+ being the connection's source.
|
||||
+
|
||||
+ audio-widgets:
|
||||
+ $ref: /schemas/types.yaml#/definitions/non-unique-string-array
|
||||
+ minItems: 2
|
||||
+ description: |-
|
||||
+ A list off component DAPM widget. Each entry is a pair of strings,
|
||||
+ the first being the widget type, the second being the widget name
|
||||
+
|
||||
+ model:
|
||||
+ $ref: /schemas/types.yaml#/definitions/string
|
||||
+ description: User specified audio sound card name
|
||||
+
|
||||
+patternProperties:
|
||||
+ "^dai-link-[0-9]+$":
|
||||
+ type: object
|
||||
+ description: |-
|
||||
+ dai-link child nodes:
|
||||
+ Container for dai-link level properties and the CODEC sub-nodes.
|
||||
+ There should be at least one (and probably more) subnode of this type
|
||||
+
|
||||
+ properties:
|
||||
+ dai-format:
|
||||
+ $ref: /schemas/types.yaml#/definitions/string
|
||||
+ enum: [ i2s, left-j, dsp_a ]
|
||||
+
|
||||
+ mclk-fs:
|
||||
+ $ref: /schemas/types.yaml#/definitions/uint32
|
||||
+ description: |-
|
||||
+ Multiplication factor between the frame rate and master clock
|
||||
+ rate
|
||||
+
|
||||
+ sound-dai:
|
||||
+ $ref: /schemas/types.yaml#/definitions/phandle
|
||||
+ description: phandle of the CPU DAI
|
||||
+
|
||||
+ patternProperties:
|
||||
+ "^codec-[0-9]+$":
|
||||
+ type: object
|
||||
+ description: |-
|
||||
+ Codecs:
|
||||
+ dai-link representing backend links should have at least one subnode.
|
||||
+ One subnode for each codec of the dai-link. dai-link representing
|
||||
+ frontend links have no codec, therefore have no subnodes
|
||||
+
|
||||
+ properties:
|
||||
+ sound-dai:
|
||||
+ $ref: /schemas/types.yaml#/definitions/phandle
|
||||
+ description: phandle of the codec DAI
|
||||
+
|
||||
+ required:
|
||||
+ - sound-dai
|
||||
+
|
||||
+ required:
|
||||
+ - sound-dai
|
||||
+
|
||||
+required:
|
||||
+ - model
|
||||
+ - dai-link-0
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ sound {
|
||||
+ compatible = "amlogic,gx-sound-card";
|
||||
+ model = "GXL-ACME-S905X-FOO";
|
||||
+ audio-aux-devs = <&>;
|
||||
+ audio-routing = "I2S ENCODER I2S IN", "I2S FIFO Playback";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&i2s_fifo>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&i2s_encoder>;
|
||||
+ dai-format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&codec0>;
|
||||
+ };
|
||||
+
|
||||
+ codec-1 {
|
||||
+ sound-dai = <&codec1>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,202 +0,0 @@
|
||||
From 5e137ff2cdafade10881b0197e4d1b27319a418f Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 13 Feb 2020 16:51:59 +0100
|
||||
Subject: [PATCH 021/146] FROMGIT: ASoC: meson: gx: add sound card support
|
||||
|
||||
Add support for the sound card used on the amlogic GX SoC family
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 7 ++
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/gx-card.c | 141 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 150 insertions(+)
|
||||
create mode 100644 sound/soc/meson/gx-card.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 347fa78e309a..22d2af75b59e 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -101,6 +101,13 @@ config SND_MESON_CARD_UTILS
|
||||
config SND_MESON_CODEC_GLUE
|
||||
tristate
|
||||
|
||||
+config SND_MESON_GX_SOUND_CARD
|
||||
+ tristate "Amlogic GX Sound Card Support"
|
||||
+ select SND_MESON_CARD_UTILS
|
||||
+ imply SND_MESON_AIU
|
||||
+ help
|
||||
+ Select Y or M to add support for the GXBB/GXL SoC sound card
|
||||
+
|
||||
config SND_MESON_G12A_TOHDMITX
|
||||
tristate "Amlogic G12A To HDMI TX Control Support"
|
||||
select REGMAP_MMIO
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index bef2b72fd7a7..f9c90c391498 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -21,6 +21,7 @@ snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
|
||||
snd-soc-meson-axg-pdm-objs := axg-pdm.o
|
||||
snd-soc-meson-card-utils-objs := meson-card-utils.o
|
||||
snd-soc-meson-codec-glue-objs := meson-codec-glue.o
|
||||
+snd-soc-meson-gx-sound-card-objs := gx-card.o
|
||||
snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
|
||||
|
||||
obj-$(CONFIG_SND_MESON_AIU) += snd-soc-meson-aiu.o
|
||||
@@ -37,4 +38,5 @@ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
|
||||
obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
|
||||
obj-$(CONFIG_SND_MESON_CARD_UTILS) += snd-soc-meson-card-utils.o
|
||||
obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o
|
||||
+obj-$(CONFIG_SND_MESON_GX_SOUND_CARD) += snd-soc-meson-gx-sound-card.o
|
||||
obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
|
||||
diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c
|
||||
new file mode 100644
|
||||
index 000000000000..7b01dcb73e5e
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/gx-card.c
|
||||
@@ -0,0 +1,141 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
||||
+//
|
||||
+// Copyright (c) 2020 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include "meson-card.h"
|
||||
+
|
||||
+struct gx_dai_link_i2s_data {
|
||||
+ unsigned int mclk_fs;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Base params for the codec to codec links
|
||||
+ * Those will be over-written by the CPU side of the link
|
||||
+ */
|
||||
+static const struct snd_soc_pcm_stream codec_params = {
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
|
||||
+ .rate_min = 5525,
|
||||
+ .rate_max = 192000,
|
||||
+ .channels_min = 1,
|
||||
+ .channels_max = 8,
|
||||
+};
|
||||
+
|
||||
+static int gx_card_i2s_be_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
+ struct gx_dai_link_i2s_data *be =
|
||||
+ (struct gx_dai_link_i2s_data *)priv->link_data[rtd->num];
|
||||
+
|
||||
+ return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_ops gx_card_i2s_be_ops = {
|
||||
+ .hw_params = gx_card_i2s_be_hw_params,
|
||||
+};
|
||||
+
|
||||
+static int gx_card_parse_i2s(struct snd_soc_card *card,
|
||||
+ struct device_node *node,
|
||||
+ int *index)
|
||||
+{
|
||||
+ struct meson_card *priv = snd_soc_card_get_drvdata(card);
|
||||
+ struct snd_soc_dai_link *link = &card->dai_link[*index];
|
||||
+ struct gx_dai_link_i2s_data *be;
|
||||
+
|
||||
+ /* Allocate i2s link parameters */
|
||||
+ be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
|
||||
+ if (!be)
|
||||
+ return -ENOMEM;
|
||||
+ priv->link_data[*index] = be;
|
||||
+
|
||||
+ /* Setup i2s link */
|
||||
+ link->ops = &gx_card_i2s_be_ops;
|
||||
+ link->dai_fmt = meson_card_parse_daifmt(node, link->cpus->of_node);
|
||||
+
|
||||
+ of_property_read_u32(node, "mclk-fs", &be->mclk_fs);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gx_card_cpu_identify(struct snd_soc_dai_link_component *c,
|
||||
+ char *match)
|
||||
+{
|
||||
+ if (of_device_is_compatible(c->of_node, DT_PREFIX "aiu")) {
|
||||
+ if (strstr(c->dai_name, match))
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* dai not matched */
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
|
||||
+ int *index)
|
||||
+{
|
||||
+ struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
|
||||
+ struct snd_soc_dai_link_component *cpu;
|
||||
+ int ret;
|
||||
+
|
||||
+ cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
|
||||
+ if (!cpu)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dai_link->cpus = cpu;
|
||||
+ dai_link->num_cpus = 1;
|
||||
+
|
||||
+ ret = meson_card_parse_dai(card, np, &dai_link->cpus->of_node,
|
||||
+ &dai_link->cpus->dai_name);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (gx_card_cpu_identify(dai_link->cpus, "FIFO"))
|
||||
+ ret = meson_card_set_fe_link(card, dai_link, np, true);
|
||||
+ else
|
||||
+ ret = meson_card_set_be_link(card, dai_link, np);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Check if the cpu is the i2s encoder and parse i2s data */
|
||||
+ if (gx_card_cpu_identify(dai_link->cpus, "I2S Encoder"))
|
||||
+ ret = gx_card_parse_i2s(card, np, index);
|
||||
+
|
||||
+ /* Or apply codec to codec params if necessary */
|
||||
+ else if (gx_card_cpu_identify(dai_link->cpus, "CODEC CTRL"))
|
||||
+ dai_link->params = &codec_params;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct meson_card_match_data gx_card_match_data = {
|
||||
+ .add_link = gx_card_add_link,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id gx_card_of_match[] = {
|
||||
+ {
|
||||
+ .compatible = "amlogic,gx-sound-card",
|
||||
+ .data = &gx_card_match_data,
|
||||
+ }, {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, gx_card_of_match);
|
||||
+
|
||||
+static struct platform_driver gx_card_pdrv = {
|
||||
+ .probe = meson_card_probe,
|
||||
+ .remove = meson_card_remove,
|
||||
+ .driver = {
|
||||
+ .name = "gx-sound-card",
|
||||
+ .of_match_table = gx_card_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(gx_card_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Amlogic GX ALSA machine driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,36 +0,0 @@
|
||||
From 5c2913e476788639e41b07bbb8f60ee74a4a5db4 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 02:47:55 +0000
|
||||
Subject: [PATCH 022/146] FROMGIT: ASoC: meson: aiu: remove unused encoder
|
||||
structure
|
||||
|
||||
Remove an unused structure definition which slipped through the initial
|
||||
driver submission.
|
||||
|
||||
Fixes: 6ae9ca9ce986 ("ASoC: meson: aiu: add i2s and spdif support")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu-encoder-i2s.c | 7 -------
|
||||
1 file changed, 7 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
|
||||
index 13bf029086a9..4900e38e7e49 100644
|
||||
--- a/sound/soc/meson/aiu-encoder-i2s.c
|
||||
+++ b/sound/soc/meson/aiu-encoder-i2s.c
|
||||
@@ -28,13 +28,6 @@
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV GENMASK(5, 0)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV GENMASK(11, 0)
|
||||
|
||||
-struct aiu_encoder_i2s {
|
||||
- struct clk *aoclk;
|
||||
- struct clk *mclk;
|
||||
- struct clk *mixer;
|
||||
- struct clk *pclk;
|
||||
-};
|
||||
-
|
||||
static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
|
||||
bool enable)
|
||||
{
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,31 +0,0 @@
|
||||
From 1760f0adce918aae57e9cc292b10b891e55fb629 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 02:51:14 +0000
|
||||
Subject: [PATCH 023/146] FROMGIT: ASoC: meson: aiu: fix clk bulk size
|
||||
allocation
|
||||
|
||||
Fix the size of allocated memory for the clock bulk data
|
||||
|
||||
Fixes: 6ae9ca9ce986 ("ASoC: meson: aiu: add i2s and spdif support")
|
||||
Reported-by: kbuild test robot <lkp@intel.com>
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
|
||||
index 5c4845a23a34..de678a9d5cab 100644
|
||||
--- a/sound/soc/meson/aiu.c
|
||||
+++ b/sound/soc/meson/aiu.c
|
||||
@@ -203,7 +203,7 @@ static int aiu_clk_bulk_get(struct device *dev,
|
||||
struct clk_bulk_data *clks;
|
||||
int i, ret;
|
||||
|
||||
- clks = devm_kcalloc(dev, num, sizeof(clks), GFP_KERNEL);
|
||||
+ clks = devm_kcalloc(dev, num, sizeof(*clks), GFP_KERNEL);
|
||||
if (!clks)
|
||||
return -ENOMEM;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,59 +0,0 @@
|
||||
From 94ffe149b3fcf237b440afc7475c5160ee050fe1 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 02:52:13 +0000
|
||||
Subject: [PATCH 024/146] FROMGIT: ASoC: meson: aiu: fix irq registration
|
||||
|
||||
The aiu stored the irq in an unsigned integer which may have discarded an
|
||||
error returned by platform_get_irq_byname(). This is incorrect and should
|
||||
have been a signed integer.
|
||||
|
||||
Also drop the irq error traces from the probe function as this is already
|
||||
done by platform_get_irq_byname().
|
||||
|
||||
Fixes: 6ae9ca9ce986 ("ASoC: meson: aiu: add i2s and spdif support")
|
||||
Reported-by: kbuild test robot <lkp@intel.com>
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu.c | 8 ++------
|
||||
sound/soc/meson/aiu.h | 2 +-
|
||||
2 files changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
|
||||
index de678a9d5cab..34b40b8b8299 100644
|
||||
--- a/sound/soc/meson/aiu.c
|
||||
+++ b/sound/soc/meson/aiu.c
|
||||
@@ -314,16 +314,12 @@ static int aiu_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
aiu->i2s.irq = platform_get_irq_byname(pdev, "i2s");
|
||||
- if (aiu->i2s.irq < 0) {
|
||||
- dev_err(dev, "Can't get i2s irq\n");
|
||||
+ if (aiu->i2s.irq < 0)
|
||||
return aiu->i2s.irq;
|
||||
- }
|
||||
|
||||
aiu->spdif.irq = platform_get_irq_byname(pdev, "spdif");
|
||||
- if (aiu->spdif.irq < 0) {
|
||||
- dev_err(dev, "Can't get spdif irq\n");
|
||||
+ if (aiu->spdif.irq < 0)
|
||||
return aiu->spdif.irq;
|
||||
- }
|
||||
|
||||
ret = aiu_clk_get(dev);
|
||||
if (ret)
|
||||
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
|
||||
index a65a576e3400..097c26de7b7c 100644
|
||||
--- a/sound/soc/meson/aiu.h
|
||||
+++ b/sound/soc/meson/aiu.h
|
||||
@@ -26,7 +26,7 @@ enum aiu_clk_ids {
|
||||
struct aiu_interface {
|
||||
struct clk_bulk_data *clks;
|
||||
unsigned int clk_num;
|
||||
- unsigned int irq;
|
||||
+ int irq;
|
||||
};
|
||||
|
||||
struct aiu {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,30 +0,0 @@
|
||||
From 1ba9f7539547f066632ac14ec70edff578392904 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 02:53:13 +0000
|
||||
Subject: [PATCH 025/146] FROMGIT: ASoC: meson: aiu: fix acodec dai input name
|
||||
init
|
||||
|
||||
Remove the double initialization of the dai input name as reported by
|
||||
sparse.
|
||||
|
||||
Fixes: 65816025d461 ("ASoC: meson: aiu: add internal dac codec control support")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu-acodec-ctrl.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
index 12d8a4d351a1..b8e88b1a4fc8 100644
|
||||
--- a/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
+++ b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
@@ -128,7 +128,6 @@ static const struct snd_soc_dai_ops aiu_acodec_ctrl_output_ops = {
|
||||
|
||||
#define AIU_ACODEC_INPUT(xname) { \
|
||||
.name = "ACODEC CTRL " xname, \
|
||||
- .name = xname, \
|
||||
.playback = AIU_ACODEC_STREAM(xname, "Playback", 8), \
|
||||
.ops = &aiu_acodec_ctrl_input_ops, \
|
||||
.probe = meson_codec_glue_input_dai_probe, \
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 8c5b9df1893669b287e9203a15b6da099d59573e Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 02:54:18 +0000
|
||||
Subject: [PATCH 026/146] FROMGIT: ASoC: meson: codec-glue: fix pcm format cast
|
||||
warning
|
||||
|
||||
Clarify the cast of snd_pcm_format_t and fix the sparse warning:
|
||||
restricted snd_pcm_format_t degrades to integer
|
||||
|
||||
Fixes: 9c29fd9bdf92 ("ASoC: meson: g12a: extract codec-to-codec utils")
|
||||
Reported-by: kbuild test robot <lkp@intel.com>
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/meson-codec-glue.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
|
||||
index 97bbc967e176..524a33472337 100644
|
||||
--- a/sound/soc/meson/meson-codec-glue.c
|
||||
+++ b/sound/soc/meson/meson-codec-glue.c
|
||||
@@ -74,7 +74,7 @@ int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
|
||||
data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
|
||||
data->params.rate_min = params_rate(params);
|
||||
data->params.rate_max = params_rate(params);
|
||||
- data->params.formats = 1 << params_format(params);
|
||||
+ data->params.formats = 1ULL << (__force int) params_format(params);
|
||||
data->params.channels_min = params_channels(params);
|
||||
data->params.channels_max = params_channels(params);
|
||||
data->params.sig_bits = dai->driver->playback.sig_bits;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,113 +0,0 @@
|
||||
From 9a99b4ea1ffa2c15a9c8b4b7ab483baa5d5d2075 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 17 Feb 2020 17:16:47 +0000
|
||||
Subject: [PATCH 027/146] FROMGIT: ASoC: meson: aiu: simplify component
|
||||
addition
|
||||
|
||||
Now that the component name is unique within ASoC, there is no need to
|
||||
hack the debugfs prefix to add more than one ASoC component to a linux
|
||||
device. Remove the unnecessary function and use
|
||||
snd_soc_register_component() directly.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu-acodec-ctrl.c | 7 +++----
|
||||
sound/soc/meson/aiu-codec-ctrl.c | 7 +++----
|
||||
sound/soc/meson/aiu.c | 20 --------------------
|
||||
sound/soc/meson/aiu.h | 8 --------
|
||||
4 files changed, 6 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
index b8e88b1a4fc8..7078197e0cc5 100644
|
||||
--- a/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
+++ b/sound/soc/meson/aiu-acodec-ctrl.c
|
||||
@@ -197,8 +197,7 @@ static const struct snd_soc_component_driver aiu_acodec_ctrl_component = {
|
||||
|
||||
int aiu_acodec_ctrl_register_component(struct device *dev)
|
||||
{
|
||||
- return aiu_add_component(dev, &aiu_acodec_ctrl_component,
|
||||
- aiu_acodec_ctrl_dai_drv,
|
||||
- ARRAY_SIZE(aiu_acodec_ctrl_dai_drv),
|
||||
- "acodec");
|
||||
+ return snd_soc_register_component(dev, &aiu_acodec_ctrl_component,
|
||||
+ aiu_acodec_ctrl_dai_drv,
|
||||
+ ARRAY_SIZE(aiu_acodec_ctrl_dai_drv));
|
||||
}
|
||||
diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c
|
||||
index 8646a953e3b3..4b773d3e8b07 100644
|
||||
--- a/sound/soc/meson/aiu-codec-ctrl.c
|
||||
+++ b/sound/soc/meson/aiu-codec-ctrl.c
|
||||
@@ -144,9 +144,8 @@ static const struct snd_soc_component_driver aiu_hdmi_ctrl_component = {
|
||||
|
||||
int aiu_hdmi_ctrl_register_component(struct device *dev)
|
||||
{
|
||||
- return aiu_add_component(dev, &aiu_hdmi_ctrl_component,
|
||||
- aiu_hdmi_ctrl_dai_drv,
|
||||
- ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv),
|
||||
- "hdmi");
|
||||
+ return snd_soc_register_component(dev, &aiu_hdmi_ctrl_component,
|
||||
+ aiu_hdmi_ctrl_dai_drv,
|
||||
+ ARRAY_SIZE(aiu_hdmi_ctrl_dai_drv));
|
||||
}
|
||||
|
||||
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
|
||||
index 34b40b8b8299..d3e2d40e9562 100644
|
||||
--- a/sound/soc/meson/aiu.c
|
||||
+++ b/sound/soc/meson/aiu.c
|
||||
@@ -71,26 +71,6 @@ int aiu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int aiu_add_component(struct device *dev,
|
||||
- const struct snd_soc_component_driver *component_driver,
|
||||
- struct snd_soc_dai_driver *dai_drv,
|
||||
- int num_dai,
|
||||
- const char *debugfs_prefix)
|
||||
-{
|
||||
- struct snd_soc_component *component;
|
||||
-
|
||||
- component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
|
||||
- if (!component)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
-#ifdef CONFIG_DEBUG_FS
|
||||
- component->debugfs_prefix = debugfs_prefix;
|
||||
-#endif
|
||||
-
|
||||
- return snd_soc_add_component(dev, component, component_driver,
|
||||
- dai_drv, num_dai);
|
||||
-}
|
||||
-
|
||||
static int aiu_cpu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
struct of_phandle_args *args,
|
||||
const char **dai_name)
|
||||
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
|
||||
index 097c26de7b7c..06a968c55728 100644
|
||||
--- a/sound/soc/meson/aiu.h
|
||||
+++ b/sound/soc/meson/aiu.h
|
||||
@@ -11,9 +11,7 @@ struct clk;
|
||||
struct clk_bulk_data;
|
||||
struct device;
|
||||
struct of_phandle_args;
|
||||
-struct snd_soc_component_driver;
|
||||
struct snd_soc_dai;
|
||||
-struct snd_soc_dai_driver;
|
||||
struct snd_soc_dai_ops;
|
||||
|
||||
enum aiu_clk_ids {
|
||||
@@ -45,12 +43,6 @@ int aiu_of_xlate_dai_name(struct snd_soc_component *component,
|
||||
const char **dai_name,
|
||||
unsigned int component_id);
|
||||
|
||||
-int aiu_add_component(struct device *dev,
|
||||
- const struct snd_soc_component_driver *component_driver,
|
||||
- struct snd_soc_dai_driver *dai_drv,
|
||||
- int num_dai,
|
||||
- const char *debugfs_prefix);
|
||||
-
|
||||
int aiu_hdmi_ctrl_register_component(struct device *dev);
|
||||
int aiu_acodec_ctrl_register_component(struct device *dev);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,33 +0,0 @@
|
||||
From d7ed18c0cb5c844464928fb00e9dcb5e59fb0bd1 Mon Sep 17 00:00:00 2001
|
||||
From: Guillaume La Roque <glaroque@baylibre.com>
|
||||
Date: Fri, 17 Jan 2020 14:34:23 +0100
|
||||
Subject: [PATCH 028/146] FROMGIT: arm64: dts: meson-sm1-sei610: add missing
|
||||
interrupt-names
|
||||
|
||||
add missing "host-wakeup interrupt names
|
||||
|
||||
Fixes: 30388cc07572 ("arm64: dts: meson-sm1-sei610: add gpio bluetooth interrupt")
|
||||
|
||||
Signed-off-by: Guillaume La Roque <glaroque@baylibre.com>
|
||||
Acked-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Link: https://lore.kernel.org/r/20200117133423.22602-1-glaroque@baylibre.com
|
||||
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
|
||||
index a8bb3fa9fec9..cb1b48f5b8b1 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
|
||||
@@ -593,6 +593,7 @@
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
interrupt-parent = <&gpio_intc>;
|
||||
interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ interrupt-names = "host-wakeup";
|
||||
shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
|
||||
max-speed = <2000000>;
|
||||
clocks = <&wifi32k>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,46 +0,0 @@
|
||||
From 9c7dd0fbffecbe8ba36083c9e3a8d42a86016205 Mon Sep 17 00:00:00 2001
|
||||
From: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Date: Wed, 15 Jan 2020 19:30:28 +0800
|
||||
Subject: [PATCH 029/146] FROMGIT: firmware: meson_sm: Add secure power domain
|
||||
support
|
||||
|
||||
The Amlogic Meson A1/C1 Secure Monitor implements calls to control power
|
||||
domain.
|
||||
|
||||
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
|
||||
Link: https://lore.kernel.org/r/1579087831-94965-2-git-send-email-jianxin.pan@amlogic.com
|
||||
---
|
||||
drivers/firmware/meson/meson_sm.c | 2 ++
|
||||
include/linux/firmware/meson/meson_sm.h | 2 ++
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
|
||||
index 1d5b4d74f96d..2854b56f6e0b 100644
|
||||
--- a/drivers/firmware/meson/meson_sm.c
|
||||
+++ b/drivers/firmware/meson/meson_sm.c
|
||||
@@ -44,6 +44,8 @@ static const struct meson_sm_chip gxbb_chip = {
|
||||
CMD(SM_EFUSE_WRITE, 0x82000031),
|
||||
CMD(SM_EFUSE_USER_MAX, 0x82000033),
|
||||
CMD(SM_GET_CHIP_ID, 0x82000044),
|
||||
+ CMD(SM_A1_PWRC_SET, 0x82000093),
|
||||
+ CMD(SM_A1_PWRC_GET, 0x82000095),
|
||||
{ /* sentinel */ },
|
||||
},
|
||||
};
|
||||
diff --git a/include/linux/firmware/meson/meson_sm.h b/include/linux/firmware/meson/meson_sm.h
|
||||
index 6669e2a1d5fd..95b0da2326a9 100644
|
||||
--- a/include/linux/firmware/meson/meson_sm.h
|
||||
+++ b/include/linux/firmware/meson/meson_sm.h
|
||||
@@ -12,6 +12,8 @@ enum {
|
||||
SM_EFUSE_WRITE,
|
||||
SM_EFUSE_USER_MAX,
|
||||
SM_GET_CHIP_ID,
|
||||
+ SM_A1_PWRC_SET,
|
||||
+ SM_A1_PWRC_GET,
|
||||
};
|
||||
|
||||
struct meson_sm_firmware;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,110 +0,0 @@
|
||||
From c09c38353f182231d63589ba32f6af56a3187dad Mon Sep 17 00:00:00 2001
|
||||
From: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Date: Wed, 15 Jan 2020 19:30:29 +0800
|
||||
Subject: [PATCH 030/146] FROMGIT: dt-bindings: power: add Amlogic secure power
|
||||
domains bindings
|
||||
|
||||
Add the bindings for the Amlogic Secure power domains, controlling the
|
||||
secure power domains.
|
||||
|
||||
The bindings targets the Amlogic A1 and C1 compatible SoCs, in which the
|
||||
power domain registers are in secure world.
|
||||
|
||||
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
|
||||
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||
Link: https://lore.kernel.org/r/1579087831-94965-3-git-send-email-jianxin.pan@amlogic.com
|
||||
---
|
||||
.../power/amlogic,meson-sec-pwrc.yaml | 40 +++++++++++++++++++
|
||||
include/dt-bindings/power/meson-a1-power.h | 32 +++++++++++++++
|
||||
2 files changed, 72 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml
|
||||
create mode 100644 include/dt-bindings/power/meson-a1-power.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml
|
||||
new file mode 100644
|
||||
index 000000000000..af32209218bb
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml
|
||||
@@ -0,0 +1,40 @@
|
||||
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
+# Copyright (c) 2019 Amlogic, Inc
|
||||
+# Author: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-pwrc.yaml#"
|
||||
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
+
|
||||
+title: Amlogic Meson Secure Power Domains
|
||||
+
|
||||
+maintainers:
|
||||
+ - Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
+
|
||||
+description: |+
|
||||
+ Secure Power Domains used in Meson A1/C1 SoCs, and should be the child node
|
||||
+ of secure-monitor.
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ enum:
|
||||
+ - amlogic,meson-a1-pwrc
|
||||
+
|
||||
+ "#power-domain-cells":
|
||||
+ const: 1
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+ - "#power-domain-cells"
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ secure-monitor {
|
||||
+ compatible = "amlogic,meson-gxbb-sm";
|
||||
+
|
||||
+ pwrc: power-controller {
|
||||
+ compatible = "amlogic,meson-a1-pwrc";
|
||||
+ #power-domain-cells = <1>;
|
||||
+ };
|
||||
+ }
|
||||
+
|
||||
diff --git a/include/dt-bindings/power/meson-a1-power.h b/include/dt-bindings/power/meson-a1-power.h
|
||||
new file mode 100644
|
||||
index 000000000000..6cf50bfb8ccf
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/power/meson-a1-power.h
|
||||
@@ -0,0 +1,32 @@
|
||||
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
|
||||
+/*
|
||||
+ * Copyright (c) 2019 Amlogic, Inc.
|
||||
+ * Author: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef _DT_BINDINGS_MESON_A1_POWER_H
|
||||
+#define _DT_BINDINGS_MESON_A1_POWER_H
|
||||
+
|
||||
+#define PWRC_DSPA_ID 8
|
||||
+#define PWRC_DSPB_ID 9
|
||||
+#define PWRC_UART_ID 10
|
||||
+#define PWRC_DMC_ID 11
|
||||
+#define PWRC_I2C_ID 12
|
||||
+#define PWRC_PSRAM_ID 13
|
||||
+#define PWRC_ACODEC_ID 14
|
||||
+#define PWRC_AUDIO_ID 15
|
||||
+#define PWRC_OTP_ID 16
|
||||
+#define PWRC_DMA_ID 17
|
||||
+#define PWRC_SD_EMMC_ID 18
|
||||
+#define PWRC_RAMA_ID 19
|
||||
+#define PWRC_RAMB_ID 20
|
||||
+#define PWRC_IR_ID 21
|
||||
+#define PWRC_SPICC_ID 22
|
||||
+#define PWRC_SPIFC_ID 23
|
||||
+#define PWRC_USB_ID 24
|
||||
+#define PWRC_NIC_ID 25
|
||||
+#define PWRC_PDMIN_ID 26
|
||||
+#define PWRC_RSA_ID 27
|
||||
+#define PWRC_MAX_ID 28
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,265 +0,0 @@
|
||||
From 8d1db083028d67823dc8339cb801bb832304aac2 Mon Sep 17 00:00:00 2001
|
||||
From: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Date: Wed, 15 Jan 2020 19:30:30 +0800
|
||||
Subject: [PATCH 031/146] FROMGIT: soc: amlogic: Add support for Secure power
|
||||
domains controller
|
||||
|
||||
Add support for the Amlogic Secure Power controller. In A1/C1 series, power
|
||||
control registers are in secure domain, and should be accessed by smc.
|
||||
|
||||
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
|
||||
Link: https://lore.kernel.org/r/1579087831-94965-4-git-send-email-jianxin.pan@amlogic.com
|
||||
---
|
||||
drivers/soc/amlogic/Kconfig | 13 ++
|
||||
drivers/soc/amlogic/Makefile | 1 +
|
||||
drivers/soc/amlogic/meson-secure-pwrc.c | 204 ++++++++++++++++++++++++
|
||||
3 files changed, 218 insertions(+)
|
||||
create mode 100644 drivers/soc/amlogic/meson-secure-pwrc.c
|
||||
|
||||
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
|
||||
index bc2c912949bd..6cb06e7b5e63 100644
|
||||
--- a/drivers/soc/amlogic/Kconfig
|
||||
+++ b/drivers/soc/amlogic/Kconfig
|
||||
@@ -48,6 +48,19 @@ config MESON_EE_PM_DOMAINS
|
||||
Say yes to expose Amlogic Meson Everything-Else Power Domains as
|
||||
Generic Power Domains.
|
||||
|
||||
+config MESON_SECURE_PM_DOMAINS
|
||||
+ bool "Amlogic Meson Secure Power Domains driver"
|
||||
+ depends on ARCH_MESON || COMPILE_TEST
|
||||
+ depends on PM && OF
|
||||
+ depends on HAVE_ARM_SMCCC
|
||||
+ default ARCH_MESON
|
||||
+ select PM_GENERIC_DOMAINS
|
||||
+ select PM_GENERIC_DOMAINS_OF
|
||||
+ help
|
||||
+ Support for the power controller on Amlogic A1/C1 series.
|
||||
+ Say yes to expose Amlogic Meson Secure Power Domains as Generic
|
||||
+ Power Domains.
|
||||
+
|
||||
config MESON_MX_SOCINFO
|
||||
bool "Amlogic Meson MX SoC Information driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
|
||||
index de79d044b545..7b8c5d323f5c 100644
|
||||
--- a/drivers/soc/amlogic/Makefile
|
||||
+++ b/drivers/soc/amlogic/Makefile
|
||||
@@ -5,3 +5,4 @@ obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
|
||||
obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
|
||||
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
|
||||
obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
|
||||
+obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o
|
||||
diff --git a/drivers/soc/amlogic/meson-secure-pwrc.c b/drivers/soc/amlogic/meson-secure-pwrc.c
|
||||
new file mode 100644
|
||||
index 000000000000..5fb29a475879
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/amlogic/meson-secure-pwrc.c
|
||||
@@ -0,0 +1,204 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
+/*
|
||||
+ * Copyright (c) 2019 Amlogic, Inc.
|
||||
+ * Author: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pm_domain.h>
|
||||
+#include <dt-bindings/power/meson-a1-power.h>
|
||||
+#include <linux/arm-smccc.h>
|
||||
+#include <linux/firmware/meson/meson_sm.h>
|
||||
+
|
||||
+#define PWRC_ON 1
|
||||
+#define PWRC_OFF 0
|
||||
+
|
||||
+struct meson_secure_pwrc_domain {
|
||||
+ struct generic_pm_domain base;
|
||||
+ unsigned int index;
|
||||
+ struct meson_secure_pwrc *pwrc;
|
||||
+};
|
||||
+
|
||||
+struct meson_secure_pwrc {
|
||||
+ struct meson_secure_pwrc_domain *domains;
|
||||
+ struct genpd_onecell_data xlate;
|
||||
+ struct meson_sm_firmware *fw;
|
||||
+};
|
||||
+
|
||||
+struct meson_secure_pwrc_domain_desc {
|
||||
+ unsigned int index;
|
||||
+ unsigned int flags;
|
||||
+ char *name;
|
||||
+ bool (*is_off)(struct meson_secure_pwrc_domain *pwrc_domain);
|
||||
+};
|
||||
+
|
||||
+struct meson_secure_pwrc_domain_data {
|
||||
+ unsigned int count;
|
||||
+ struct meson_secure_pwrc_domain_desc *domains;
|
||||
+};
|
||||
+
|
||||
+static bool pwrc_secure_is_off(struct meson_secure_pwrc_domain *pwrc_domain)
|
||||
+{
|
||||
+ int is_off = 1;
|
||||
+
|
||||
+ if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_GET, &is_off,
|
||||
+ pwrc_domain->index, 0, 0, 0, 0) < 0)
|
||||
+ pr_err("failed to get power domain status\n");
|
||||
+
|
||||
+ return is_off;
|
||||
+}
|
||||
+
|
||||
+static int meson_secure_pwrc_off(struct generic_pm_domain *domain)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct meson_secure_pwrc_domain *pwrc_domain =
|
||||
+ container_of(domain, struct meson_secure_pwrc_domain, base);
|
||||
+
|
||||
+ if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
|
||||
+ pwrc_domain->index, PWRC_OFF, 0, 0, 0) < 0) {
|
||||
+ pr_err("failed to set power domain off\n");
|
||||
+ ret = -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int meson_secure_pwrc_on(struct generic_pm_domain *domain)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct meson_secure_pwrc_domain *pwrc_domain =
|
||||
+ container_of(domain, struct meson_secure_pwrc_domain, base);
|
||||
+
|
||||
+ if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL,
|
||||
+ pwrc_domain->index, PWRC_ON, 0, 0, 0) < 0) {
|
||||
+ pr_err("failed to set power domain on\n");
|
||||
+ ret = -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#define SEC_PD(__name, __flag) \
|
||||
+[PWRC_##__name##_ID] = \
|
||||
+{ \
|
||||
+ .name = #__name, \
|
||||
+ .index = PWRC_##__name##_ID, \
|
||||
+ .is_off = pwrc_secure_is_off, \
|
||||
+ .flags = __flag, \
|
||||
+}
|
||||
+
|
||||
+static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = {
|
||||
+ SEC_PD(DSPA, 0),
|
||||
+ SEC_PD(DSPB, 0),
|
||||
+ /* UART should keep working in ATF after suspend and before resume */
|
||||
+ SEC_PD(UART, GENPD_FLAG_ALWAYS_ON),
|
||||
+ /* DMC is for DDR PHY ana/dig and DMC, and should be always on */
|
||||
+ SEC_PD(DMC, GENPD_FLAG_ALWAYS_ON),
|
||||
+ SEC_PD(I2C, 0),
|
||||
+ SEC_PD(PSRAM, 0),
|
||||
+ SEC_PD(ACODEC, 0),
|
||||
+ SEC_PD(AUDIO, 0),
|
||||
+ SEC_PD(OTP, 0),
|
||||
+ SEC_PD(DMA, 0),
|
||||
+ SEC_PD(SD_EMMC, 0),
|
||||
+ SEC_PD(RAMA, 0),
|
||||
+ /* SRAMB is used as ATF runtime memory, and should be always on */
|
||||
+ SEC_PD(RAMB, GENPD_FLAG_ALWAYS_ON),
|
||||
+ SEC_PD(IR, 0),
|
||||
+ SEC_PD(SPICC, 0),
|
||||
+ SEC_PD(SPIFC, 0),
|
||||
+ SEC_PD(USB, 0),
|
||||
+ /* NIC is for the Arm NIC-400 interconnect, and should be always on */
|
||||
+ SEC_PD(NIC, GENPD_FLAG_ALWAYS_ON),
|
||||
+ SEC_PD(PDMIN, 0),
|
||||
+ SEC_PD(RSA, 0),
|
||||
+};
|
||||
+
|
||||
+static int meson_secure_pwrc_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct device_node *sm_np;
|
||||
+ struct meson_secure_pwrc *pwrc;
|
||||
+ const struct meson_secure_pwrc_domain_data *match;
|
||||
+
|
||||
+ match = of_device_get_match_data(&pdev->dev);
|
||||
+ if (!match) {
|
||||
+ dev_err(&pdev->dev, "failed to get match data\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ sm_np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gxbb-sm");
|
||||
+ if (!sm_np) {
|
||||
+ dev_err(&pdev->dev, "no secure-monitor node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
|
||||
+ if (!pwrc)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrc->fw = meson_sm_get(sm_np);
|
||||
+ of_node_put(sm_np);
|
||||
+ if (!pwrc->fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
|
||||
+ sizeof(*pwrc->xlate.domains),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!pwrc->xlate.domains)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
|
||||
+ sizeof(*pwrc->domains), GFP_KERNEL);
|
||||
+ if (!pwrc->domains)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pwrc->xlate.num_domains = match->count;
|
||||
+ platform_set_drvdata(pdev, pwrc);
|
||||
+
|
||||
+ for (i = 0 ; i < match->count ; ++i) {
|
||||
+ struct meson_secure_pwrc_domain *dom = &pwrc->domains[i];
|
||||
+
|
||||
+ if (!match->domains[i].index)
|
||||
+ continue;
|
||||
+
|
||||
+ dom->pwrc = pwrc;
|
||||
+ dom->index = match->domains[i].index;
|
||||
+ dom->base.name = match->domains[i].name;
|
||||
+ dom->base.flags = match->domains[i].flags;
|
||||
+ dom->base.power_on = meson_secure_pwrc_on;
|
||||
+ dom->base.power_off = meson_secure_pwrc_off;
|
||||
+
|
||||
+ pm_genpd_init(&dom->base, NULL, match->domains[i].is_off(dom));
|
||||
+
|
||||
+ pwrc->xlate.domains[i] = &dom->base;
|
||||
+ }
|
||||
+
|
||||
+ return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
|
||||
+}
|
||||
+
|
||||
+static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = {
|
||||
+ .domains = a1_pwrc_domains,
|
||||
+ .count = ARRAY_SIZE(a1_pwrc_domains),
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id meson_secure_pwrc_match_table[] = {
|
||||
+ {
|
||||
+ .compatible = "amlogic,meson-a1-pwrc",
|
||||
+ .data = &meson_secure_a1_pwrc_data,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static struct platform_driver meson_secure_pwrc_driver = {
|
||||
+ .probe = meson_secure_pwrc_probe,
|
||||
+ .driver = {
|
||||
+ .name = "meson_secure_pwrc",
|
||||
+ .of_match_table = meson_secure_pwrc_match_table,
|
||||
+ },
|
||||
+};
|
||||
+builtin_platform_driver(meson_secure_pwrc_driver);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 0b4093fcfeaa133997436a41542042ebdc94d31b Mon Sep 17 00:00:00 2001
|
||||
From: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Date: Wed, 15 Jan 2020 19:30:31 +0800
|
||||
Subject: [PATCH 032/146] FROMGIT: arm64: dts: meson: a1: add secure power
|
||||
domain controller
|
||||
|
||||
Enable power domain controller for Meson A1 SoC.
|
||||
|
||||
Signed-off-by: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Link: https://lore.kernel.org/r/1579087831-94965-5-git-send-email-jianxin.pan@amlogic.com
|
||||
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-a1.dtsi | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
|
||||
index 4dec518c4dde..755b4ad15184 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi
|
||||
@@ -60,6 +60,12 @@
|
||||
|
||||
sm: secure-monitor {
|
||||
compatible = "amlogic,meson-gxbb-sm";
|
||||
+
|
||||
+ pwrc: power-controller {
|
||||
+ compatible = "amlogic,meson-a1-pwrc";
|
||||
+ #power-domain-cells = <1>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
soc {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,79 +0,0 @@
|
||||
From db99ae06c558d1e9b1ab00c078294ee5448e61af Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 28 Jan 2020 13:38:38 +0100
|
||||
Subject: [PATCH 034/146] FROMLIST: ASoC: meson: add t9015 internal codec
|
||||
binding documentation
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
.../bindings/sound/amlogic,t9015.yaml | 58 +++++++++++++++++++
|
||||
1 file changed, 58 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
|
||||
new file mode 100644
|
||||
index 000000000000..b7c38c2b5b54
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/sound/amlogic,t9015.yaml
|
||||
@@ -0,0 +1,58 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/sound/amlogic,t9015.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Amlogic T9015 Internal Audio DAC
|
||||
+
|
||||
+maintainers:
|
||||
+ - Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+properties:
|
||||
+ $nodename:
|
||||
+ pattern: "^audio-controller@.*"
|
||||
+
|
||||
+ "#sound-dai-cells":
|
||||
+ const: 0
|
||||
+
|
||||
+ compatible:
|
||||
+ items:
|
||||
+ - const: amlogic,t9015
|
||||
+
|
||||
+ clocks:
|
||||
+ items:
|
||||
+ - description: Peripheral clock
|
||||
+
|
||||
+ clock-names:
|
||||
+ items:
|
||||
+ - const: pclk
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ resets:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+required:
|
||||
+ - "#sound-dai-cells"
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+ - clocks
|
||||
+ - clock-names
|
||||
+ - resets
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ #include <dt-bindings/clock/g12a-clkc.h>
|
||||
+ #include <dt-bindings/reset/amlogic,meson-g12a-reset.h>
|
||||
+
|
||||
+ acodec: audio-controller@32000 {
|
||||
+ compatible = "amlogic,t9015";
|
||||
+ reg = <0x0 0x32000 0x0 0x14>;
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ clocks = <&clkc CLKID_AUDIO_CODEC>;
|
||||
+ clock-names = "pclk";
|
||||
+ resets = <&reset RESET_AUDIO_CODEC>;
|
||||
+ };
|
||||
+
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,392 +0,0 @@
|
||||
From d0a549baa248b9c97babc29a5f9475f62b32266c Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 14 Aug 2019 17:09:18 +0200
|
||||
Subject: [PATCH 035/146] FROMLIST: ASoC: meson: add t9015 internal DAC driver
|
||||
|
||||
Add the codec driver of the internal DAC found on Amlogic gxl, g12a and
|
||||
sm1 family.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 8 +
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/t9015.c | 326 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 336 insertions(+)
|
||||
create mode 100644 sound/soc/meson/t9015.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 22d2af75b59e..897a706dcda0 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -6,6 +6,7 @@ config SND_MESON_AIU
|
||||
tristate "Amlogic AIU"
|
||||
select SND_MESON_CODEC_GLUE
|
||||
select SND_PCM_IEC958
|
||||
+ imply SND_SOC_MESON_T9015
|
||||
imply SND_SOC_HDMI_CODEC if DRM_MESON_DW_HDMI
|
||||
help
|
||||
Select Y or M to add support for the Audio output subsystem found
|
||||
@@ -116,4 +117,11 @@ config SND_MESON_G12A_TOHDMITX
|
||||
help
|
||||
Select Y or M to add support for HDMI audio on the g12a SoC
|
||||
family
|
||||
+
|
||||
+config SND_SOC_MESON_T9015
|
||||
+ tristate "Amlogic T9015 DAC"
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for the internal DAC found
|
||||
+ on GXL, G12 and SM1 SoC family.
|
||||
endmenu
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index f9c90c391498..3c9d48846816 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -23,6 +23,7 @@ snd-soc-meson-card-utils-objs := meson-card-utils.o
|
||||
snd-soc-meson-codec-glue-objs := meson-codec-glue.o
|
||||
snd-soc-meson-gx-sound-card-objs := gx-card.o
|
||||
snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
|
||||
+snd-soc-meson-t9015-objs := t9015.o
|
||||
|
||||
obj-$(CONFIG_SND_MESON_AIU) += snd-soc-meson-aiu.o
|
||||
obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
|
||||
@@ -40,3 +41,4 @@ obj-$(CONFIG_SND_MESON_CARD_UTILS) += snd-soc-meson-card-utils.o
|
||||
obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o
|
||||
obj-$(CONFIG_SND_MESON_GX_SOUND_CARD) += snd-soc-meson-gx-sound-card.o
|
||||
obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
|
||||
+obj-$(CONFIG_SND_SOC_MESON_T9015) += snd-soc-meson-t9015.o
|
||||
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
|
||||
new file mode 100644
|
||||
index 000000000000..4f26708b6adc
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/t9015.c
|
||||
@@ -0,0 +1,326 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// Copyright (c) 2020 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/tlv.h>
|
||||
+
|
||||
+#define BLOCK_EN 0x00
|
||||
+#define LORN_EN 0
|
||||
+#define LORP_EN 1
|
||||
+#define LOLN_EN 2
|
||||
+#define LOLP_EN 3
|
||||
+#define DACR_EN 4
|
||||
+#define DACL_EN 5
|
||||
+
|
||||
+#define DACR_INV 20
|
||||
+#define DACL_INV 21
|
||||
+#define DACR_SRC 22
|
||||
+#define DACL_SRC 23
|
||||
+#define REFP_BUF_EN BIT(12)
|
||||
+#define BIAS_CURRENT_EN BIT(13)
|
||||
+#define VMID_GEN_FAST BIT(14)
|
||||
+#define VMID_GEN_EN BIT(15)
|
||||
+#define I2S_MODE BIT(30)
|
||||
+#define VOL_CTRL0 0x04
|
||||
+#define GAIN_H 31
|
||||
+#define GAIN_L 23
|
||||
+#define VOL_CTRL1 0x08
|
||||
+#define DAC_MONO 8
|
||||
+#define RAMP_RATE 10
|
||||
+#define VC_RAMP_MODE 12
|
||||
+#define MUTE_MODE 13
|
||||
+#define UNMUTE_MODE 14
|
||||
+#define DAC_SOFT_MUTE 15
|
||||
+#define DACR_VC 16
|
||||
+#define DACL_VC 24
|
||||
+#define LINEOUT_CFG 0x0c
|
||||
+#define LORN_POL 0
|
||||
+#define LORP_POL 4
|
||||
+#define LOLN_POL 8
|
||||
+#define LOLP_POL 12
|
||||
+#define POWER_CFG 0x10
|
||||
+
|
||||
+struct t9015 {
|
||||
+ struct clk *pclk;
|
||||
+ struct regulator *avdd;
|
||||
+};
|
||||
+
|
||||
+static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
+{
|
||||
+ struct snd_soc_component *component = dai->component;
|
||||
+ unsigned int val;
|
||||
+
|
||||
+ switch(fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
+ case SND_SOC_DAIFMT_CBM_CFM:
|
||||
+ val = I2S_MODE;
|
||||
+ break;
|
||||
+
|
||||
+ case SND_SOC_DAIFMT_CBS_CFS:
|
||||
+ val = 0;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN, I2S_MODE, val);
|
||||
+
|
||||
+ if (((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S) &&
|
||||
+ ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_LEFT_J))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops t9015_dai_ops = {
|
||||
+ .set_fmt = t9015_dai_set_fmt,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver t9015_dai = {
|
||||
+ .name = "t9015-hifi",
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 1,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_96000,
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S8 |
|
||||
+ SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S20_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE),
|
||||
+ },
|
||||
+ .ops = &t9015_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static const DECLARE_TLV_DB_MINMAX_MUTE(dac_vol_tlv, -9525, 0);
|
||||
+
|
||||
+static const char * const ramp_rate_txt[] = { "Fast", "Slow" };
|
||||
+static SOC_ENUM_SINGLE_DECL(ramp_rate_enum, VOL_CTRL1, RAMP_RATE,
|
||||
+ ramp_rate_txt);
|
||||
+
|
||||
+static const char * const dacr_in_txt[] = { "Right", "Left" };
|
||||
+static SOC_ENUM_SINGLE_DECL(dacr_in_enum, BLOCK_EN, DACR_SRC, dacr_in_txt);
|
||||
+
|
||||
+static const char * const dacl_in_txt[] = { "Left", "Right" };
|
||||
+static SOC_ENUM_SINGLE_DECL(dacl_in_enum, BLOCK_EN, DACL_SRC, dacl_in_txt);
|
||||
+
|
||||
+static const char * const mono_txt[] = { "Stereo", "Mono"};
|
||||
+static SOC_ENUM_SINGLE_DECL(mono_enum, VOL_CTRL1, DAC_MONO, mono_txt);
|
||||
+
|
||||
+static const struct snd_kcontrol_new t9015_snd_controls[] = {
|
||||
+ /* Volume Controls */
|
||||
+ SOC_SINGLE("Playback Mute", VOL_CTRL1, DAC_SOFT_MUTE, 1, 0),
|
||||
+ SOC_DOUBLE_TLV("Playback Volume", VOL_CTRL1, DACL_VC, DACR_VC,
|
||||
+ 0xff, 0, dac_vol_tlv),
|
||||
+
|
||||
+ /* Ramp Controls */
|
||||
+ SOC_ENUM("Ramp Rate", ramp_rate_enum),
|
||||
+ SOC_SINGLE("Volume Ramp Enable", VOL_CTRL1, VC_RAMP_MODE, 1, 0),
|
||||
+ SOC_SINGLE("Mute Ramp Enable", VOL_CTRL1, MUTE_MODE, 1, 0),
|
||||
+ SOC_SINGLE("Unmute Ramp Enable", VOL_CTRL1, UNMUTE_MODE, 1, 0),
|
||||
+
|
||||
+ /* Channel Src */
|
||||
+ SOC_ENUM("Right DAC Source", dacr_in_enum),
|
||||
+ SOC_ENUM("Left DAC Source", dacl_in_enum),
|
||||
+ SOC_ENUM("Channel Mode", mono_enum),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget t9015_dapm_widgets[] = {
|
||||
+ SND_SOC_DAPM_DAC("Right DAC", NULL, BLOCK_EN, DACR_EN, 0),
|
||||
+ SND_SOC_DAPM_DAC("Left DAC", NULL, BLOCK_EN, DACL_EN, 0),
|
||||
+ SND_SOC_DAPM_OUT_DRV("Right- Driver", BLOCK_EN, LORN_EN, 0,
|
||||
+ NULL, 0),
|
||||
+ SND_SOC_DAPM_OUT_DRV("Right+ Driver", BLOCK_EN, LORP_EN, 0,
|
||||
+ NULL, 0),
|
||||
+ SND_SOC_DAPM_OUT_DRV("Left- Driver", BLOCK_EN, LOLN_EN, 0,
|
||||
+ NULL, 0),
|
||||
+ SND_SOC_DAPM_OUT_DRV("Left+ Driver", BLOCK_EN, LOLP_EN, 0,
|
||||
+ NULL, 0),
|
||||
+ SND_SOC_DAPM_OUTPUT("LORN"),
|
||||
+ SND_SOC_DAPM_OUTPUT("LORP"),
|
||||
+ SND_SOC_DAPM_OUTPUT("LOLN"),
|
||||
+ SND_SOC_DAPM_OUTPUT("LOLP"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route t9015_dapm_routes[] = {
|
||||
+ { "Right DAC", NULL, "Playback" },
|
||||
+ { "Left DAC", NULL, "Playback" },
|
||||
+ { "Right- Driver", NULL, "Right DAC" },
|
||||
+ { "Right+ Driver", NULL, "Right DAC" },
|
||||
+ { "Left- Driver", NULL, "Left DAC" },
|
||||
+ { "Left+ Driver", NULL, "Left DAC" },
|
||||
+ { "LORN", NULL, "Right- Driver", },
|
||||
+ { "LORP", NULL, "Right+ Driver", },
|
||||
+ { "LOLN", NULL, "Left- Driver", },
|
||||
+ { "LOLP", NULL, "Left+ Driver", },
|
||||
+};
|
||||
+
|
||||
+static int t9015_set_bias_level(struct snd_soc_component *component,
|
||||
+ enum snd_soc_bias_level level)
|
||||
+{
|
||||
+ struct t9015 *priv = snd_soc_component_get_drvdata(component);
|
||||
+ enum snd_soc_bias_level now =
|
||||
+ snd_soc_component_get_bias_level(component);
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (level) {
|
||||
+ case SND_SOC_BIAS_ON:
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN,
|
||||
+ BIAS_CURRENT_EN,
|
||||
+ BIAS_CURRENT_EN);
|
||||
+ break;
|
||||
+ case SND_SOC_BIAS_PREPARE:
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN,
|
||||
+ BIAS_CURRENT_EN,
|
||||
+ 0);
|
||||
+ break;
|
||||
+ case SND_SOC_BIAS_STANDBY:
|
||||
+ ret = regulator_enable(priv->avdd);
|
||||
+ if (ret) {
|
||||
+ dev_err(component->dev, "AVDD enable failed\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (now == SND_SOC_BIAS_OFF) {
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN,
|
||||
+ VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN,
|
||||
+ VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN);
|
||||
+
|
||||
+ mdelay(200);
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN,
|
||||
+ VMID_GEN_FAST,
|
||||
+ 0);
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
+ case SND_SOC_BIAS_OFF:
|
||||
+ snd_soc_component_update_bits(component, BLOCK_EN,
|
||||
+ VMID_GEN_EN | VMID_GEN_FAST | REFP_BUF_EN,
|
||||
+ 0);
|
||||
+
|
||||
+ regulator_disable(priv->avdd);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int t9015_component_probe(struct snd_soc_component *c)
|
||||
+{
|
||||
+ /* FIXME */
|
||||
+ return snd_soc_component_write(c, LINEOUT_CFG, 0x00001111);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver t9015_codec_driver = {
|
||||
+ .probe = t9015_component_probe,
|
||||
+ .set_bias_level = t9015_set_bias_level,
|
||||
+ .controls = t9015_snd_controls,
|
||||
+ .num_controls = ARRAY_SIZE(t9015_snd_controls),
|
||||
+ .dapm_widgets = t9015_dapm_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(t9015_dapm_widgets),
|
||||
+ .dapm_routes = t9015_dapm_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(t9015_dapm_routes),
|
||||
+ .suspend_bias_off = 1,
|
||||
+ .idle_bias_on = 1,
|
||||
+ .endianness = 1,
|
||||
+ .non_legacy_dai_naming = 1,
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config t9015_regmap_config = {
|
||||
+ .reg_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .val_bits = 32,
|
||||
+ .max_register = POWER_CFG,
|
||||
+};
|
||||
+
|
||||
+static int t9015_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct t9015 *priv;
|
||||
+ void __iomem *regs;
|
||||
+ struct regmap *regmap;
|
||||
+ int ret;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ priv->pclk = devm_clk_get(dev, "pclk");
|
||||
+ if (IS_ERR(priv->pclk)) {
|
||||
+ if (PTR_ERR(priv->pclk) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "failed to get core clock\n");
|
||||
+ return PTR_ERR(priv->pclk);
|
||||
+ }
|
||||
+
|
||||
+ priv->avdd = devm_regulator_get(dev, "AVDD");
|
||||
+ if (IS_ERR(priv->avdd)) {
|
||||
+ if (PTR_ERR(priv->avdd) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "failed to AVDD\n");
|
||||
+ return PTR_ERR(priv->avdd);
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(priv->pclk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "core clock enable failed\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev,
|
||||
+ (void(*)(void *))clk_disable_unprepare,
|
||||
+ priv->pclk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = device_reset(dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "reset failed\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(regs)) {
|
||||
+ dev_err(dev, "register map failed\n");
|
||||
+ return PTR_ERR(regs);
|
||||
+ }
|
||||
+
|
||||
+ regmap = devm_regmap_init_mmio(dev, regs, &t9015_regmap_config);
|
||||
+ if (IS_ERR(regmap)) {
|
||||
+ dev_err(dev, "regmap init failed\n");
|
||||
+ return PTR_ERR(regmap);
|
||||
+ }
|
||||
+
|
||||
+ /* Add polarity parsing here */
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &t9015_codec_driver,
|
||||
+ &t9015_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id t9015_ids[] = {
|
||||
+ { .compatible = "amlogic,t9015", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, t9015_ids);
|
||||
+
|
||||
+static struct platform_driver t9015_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "t9015-codec",
|
||||
+ .of_match_table = of_match_ptr(t9015_ids),
|
||||
+ },
|
||||
+ .probe = t9015_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(t9015_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("ASoC Amlogic T9015 codec driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
+
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 204e9f3a44134cb8c2d35fe680438217917c0b45 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 13 Jan 2020 13:50:44 +0100
|
||||
Subject: [PATCH 044/146] FROMLIST: ASoC: meson: g12a: add tohdmitx reset
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/g12a-tohdmitx.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
|
||||
index f8853f2fba08..9b2b59536ced 100644
|
||||
--- a/sound/soc/meson/g12a-tohdmitx.c
|
||||
+++ b/sound/soc/meson/g12a-tohdmitx.c
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
@@ -245,6 +246,11 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *regs;
|
||||
struct regmap *map;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = device_reset(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,92 +0,0 @@
|
||||
From dbda919875b73a65217756584bbb6bc0b055b51d Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 28 Jan 2020 13:37:39 +0100
|
||||
Subject: [PATCH 045/146] FROMLIST: ASoC: meson: add g12a-toacodec dt-binding
|
||||
documentation
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
.../bindings/sound/amlogic,g12a-toacodec.yaml | 53 +++++++++++++++++++
|
||||
.../dt-bindings/sound/meson-g12a-toacodec.h | 10 ++++
|
||||
2 files changed, 63 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
|
||||
create mode 100644 include/dt-bindings/sound/meson-g12a-toacodec.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
|
||||
new file mode 100644
|
||||
index 000000000000..cbd33ba99e58
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/sound/amlogic,g12a-toacodec.yaml
|
||||
@@ -0,0 +1,53 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/sound/amlogic,g12a-toacodec.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Amlogic G12a Internal DAC Control Glue
|
||||
+
|
||||
+maintainers:
|
||||
+ - Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+properties:
|
||||
+ $nodename:
|
||||
+ pattern: "^audio-controller@.*"
|
||||
+
|
||||
+ "#sound-dai-cells":
|
||||
+ const: 1
|
||||
+
|
||||
+ compatible:
|
||||
+ oneOf:
|
||||
+ - items:
|
||||
+ - const:
|
||||
+ amlogic,g12a-toacodec
|
||||
+ - items:
|
||||
+ - enum:
|
||||
+ - amlogic,sm1-toacodec
|
||||
+ - const:
|
||||
+ amlogic,g12a-toacodec
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ resets:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+required:
|
||||
+ - "#sound-dai-cells"
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+ - resets
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ #include <dt-bindings/reset/amlogic,meson-g12a-audio-reset.h>
|
||||
+
|
||||
+ toacodec: audio-controller@740 {
|
||||
+ compatible = "amlogic,g12a-toacodec";
|
||||
+ reg = <0x0 0x740 0x0 0x4>;
|
||||
+ #sound-dai-cells = <1>;
|
||||
+ resets = <&clkc_audio AUD_RESET_TOACODEC>;
|
||||
+ };
|
||||
+
|
||||
+
|
||||
diff --git a/include/dt-bindings/sound/meson-g12a-toacodec.h b/include/dt-bindings/sound/meson-g12a-toacodec.h
|
||||
new file mode 100644
|
||||
index 000000000000..69d7a75592a2
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/sound/meson-g12a-toacodec.h
|
||||
@@ -0,0 +1,10 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+#ifndef __DT_MESON_G12A_TOACODEC_H
|
||||
+#define __DT_MESON_G12A_TOACODEC_H
|
||||
+
|
||||
+#define TOACODEC_IN_A 0
|
||||
+#define TOACODEC_IN_B 1
|
||||
+#define TOACODEC_IN_C 2
|
||||
+#define TOACODEC_OUT 3
|
||||
+
|
||||
+#endif /* __DT_MESON_G12A_TOACODEC_H */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,301 +0,0 @@
|
||||
From 9133abee2754290bf76557f71b7fa1d4c502f404 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 12 Aug 2019 11:45:16 +0200
|
||||
Subject: [PATCH 046/146] FROMLIST: ASoC: meson: add g12 internal DAC glue
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 9 ++
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/g12a-toacodec.c | 240 ++++++++++++++++++++++++++++++++
|
||||
3 files changed, 251 insertions(+)
|
||||
create mode 100644 sound/soc/meson/g12a-toacodec.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 897a706dcda0..85ab77ff0399 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -109,6 +109,15 @@ config SND_MESON_GX_SOUND_CARD
|
||||
help
|
||||
Select Y or M to add support for the GXBB/GXL SoC sound card
|
||||
|
||||
+config SND_MESON_G12A_TOACODEC
|
||||
+ tristate "Amlogic G12A To Internal DAC Control Support"
|
||||
+ select SND_MESON_CODEC_GLUE
|
||||
+ select REGMAP_MMIO
|
||||
+ imply SND_SOC_MESON_T9015
|
||||
+ help
|
||||
+ Select Y or M to add support for the internal audio DAC on the
|
||||
+ g12a SoC family
|
||||
+
|
||||
config SND_MESON_G12A_TOHDMITX
|
||||
tristate "Amlogic G12A To HDMI TX Control Support"
|
||||
select REGMAP_MMIO
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 3c9d48846816..e446bc980481 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -22,6 +22,7 @@ snd-soc-meson-axg-pdm-objs := axg-pdm.o
|
||||
snd-soc-meson-card-utils-objs := meson-card-utils.o
|
||||
snd-soc-meson-codec-glue-objs := meson-codec-glue.o
|
||||
snd-soc-meson-gx-sound-card-objs := gx-card.o
|
||||
+snd-soc-meson-g12a-toacodec-objs := g12a-toacodec.o
|
||||
snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o
|
||||
snd-soc-meson-t9015-objs := t9015.o
|
||||
|
||||
@@ -40,5 +41,6 @@ obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o
|
||||
obj-$(CONFIG_SND_MESON_CARD_UTILS) += snd-soc-meson-card-utils.o
|
||||
obj-$(CONFIG_SND_MESON_CODEC_GLUE) += snd-soc-meson-codec-glue.o
|
||||
obj-$(CONFIG_SND_MESON_GX_SOUND_CARD) += snd-soc-meson-gx-sound-card.o
|
||||
+obj-$(CONFIG_SND_MESON_G12A_TOACODEC) += snd-soc-meson-g12a-toacodec.o
|
||||
obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_T9015) += snd-soc-meson-t9015.o
|
||||
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
|
||||
new file mode 100644
|
||||
index 000000000000..0ee074f6fc87
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/g12a-toacodec.c
|
||||
@@ -0,0 +1,240 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+//
|
||||
+// Copyright (c) 2020 BayLibre, SAS.
|
||||
+// Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include <dt-bindings/sound/meson-g12a-toacodec.h>
|
||||
+#include "axg-tdm.h"
|
||||
+#include "meson-codec-glue.h"
|
||||
+
|
||||
+#define G12A_TOACODEC_DRV_NAME "g12a-toacodec"
|
||||
+
|
||||
+#define TOACODEC_CTRL0 0x0
|
||||
+#define CTRL0_ENABLE_SHIFT 31
|
||||
+#define CTRL0_DAT_SEL GENMASK(15, 14)
|
||||
+#define CTRL0_LANE_SEL 12
|
||||
+#define CTRL0_LRCLK_SEL GENMASK(9, 8)
|
||||
+#define CTRL0_BLK_CAP_INV BIT(7)
|
||||
+#define CTRL0_BCLK_O_INV BIT(6)
|
||||
+#define CTRL0_BCLK_SEL GENMASK(5, 4)
|
||||
+#define CTRL0_MCLK_SEL GENMASK(2, 0)
|
||||
+
|
||||
+#define TOACODEC_OUT_CHMAX 2
|
||||
+
|
||||
+static const char * const g12a_toacodec_mux_texts[] = {
|
||||
+ "I2S A", "I2S B", "I2S C",
|
||||
+};
|
||||
+
|
||||
+static int g12a_toacodec_get_mux(struct snd_soc_component *component)
|
||||
+{
|
||||
+ unsigned int val;
|
||||
+
|
||||
+ snd_soc_component_read(component, TOACODEC_CTRL0, &val);
|
||||
+ return FIELD_GET(CTRL0_DAT_SEL, val);
|
||||
+}
|
||||
+
|
||||
+static int g12a_toacodec_put_mux(struct snd_soc_component *component,
|
||||
+ unsigned int mux)
|
||||
+{
|
||||
+ snd_soc_component_update_bits(component, TOACODEC_CTRL0,
|
||||
+ CTRL0_DAT_SEL |
|
||||
+ CTRL0_LRCLK_SEL |
|
||||
+ CTRL0_BCLK_SEL,
|
||||
+ FIELD_PREP(CTRL0_DAT_SEL, mux) |
|
||||
+ FIELD_PREP(CTRL0_LRCLK_SEL, mux) |
|
||||
+ FIELD_PREP(CTRL0_BCLK_SEL, mux));
|
||||
+
|
||||
+ /*
|
||||
+ * FIXME:
|
||||
+ * On this soc, the glue gets the MCLK directly from the clock
|
||||
+ * controller instead of going the through the TDM interface.
|
||||
+ *
|
||||
+ * Here we assume interface A uses clock A, etc ... While it is
|
||||
+ * true for now, it could be different. Instead the glue should
|
||||
+ * find out the clock used by the interface and select the same
|
||||
+ * source. For that, we will need regmap backed clock mux which
|
||||
+ * is a work in progress
|
||||
+ */
|
||||
+ snd_soc_component_update_bits(component, TOACODEC_CTRL0,
|
||||
+ CTRL0_MCLK_SEL,
|
||||
+ FIELD_PREP(CTRL0_MCLK_SEL, mux));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static MESON_CODEC_GLUE_ENUM_DECL(g12a_toacodec_mux_glue,
|
||||
+ g12a_toacodec_mux_texts,
|
||||
+ g12a_toacodec_get_mux,
|
||||
+ g12a_toacodec_put_mux);
|
||||
+
|
||||
+static const struct snd_kcontrol_new g12a_toacodec_mux =
|
||||
+ SOC_DAPM_ENUM_EXT("Source", g12a_toacodec_mux_enum,
|
||||
+ snd_soc_dapm_get_enum_double,
|
||||
+ g12a_toacodec_mux_put_enum);
|
||||
+
|
||||
+static const struct snd_kcontrol_new g12a_toacodec_out_enable =
|
||||
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOACODEC_CTRL0,
|
||||
+ CTRL0_ENABLE_SHIFT, 1, 0);
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget g12a_toacodec_widgets[] = {
|
||||
+ SND_SOC_DAPM_MUX("SRC", SND_SOC_NOPM, 0, 0,
|
||||
+ &g12a_toacodec_mux),
|
||||
+ SND_SOC_DAPM_SWITCH("OUT EN", SND_SOC_NOPM, 0, 0,
|
||||
+ &g12a_toacodec_out_enable),
|
||||
+};
|
||||
+
|
||||
+static int g12a_toacodec_input_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_codec_glue_input *data;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = meson_codec_glue_input_hw_params(substream, params, dai);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* The glue will provide 1 lane out of the 4 to the output */
|
||||
+ data = meson_codec_glue_input_get_data(dai);
|
||||
+ data->params.channels_min = min_t(unsigned int, TOACODEC_OUT_CHMAX,
|
||||
+ data->params.channels_min);
|
||||
+ data->params.channels_max = min_t(unsigned int, TOACODEC_OUT_CHMAX,
|
||||
+ data->params.channels_max);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops g12a_toacodec_input_ops = {
|
||||
+ .hw_params = g12a_toacodec_input_hw_params,
|
||||
+ .set_fmt = meson_codec_glue_input_set_fmt,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dai_ops g12a_toacodec_output_ops = {
|
||||
+ .startup = meson_codec_glue_output_startup,
|
||||
+};
|
||||
+
|
||||
+#define TOACODEC_STREAM(xname, xsuffix, xchmax) \
|
||||
+{ \
|
||||
+ .stream_name = xname " " xsuffix, \
|
||||
+ .channels_min = 1, \
|
||||
+ .channels_max = (xchmax), \
|
||||
+ .rate_min = 5512, \
|
||||
+ .rate_max = 192000, \
|
||||
+ .formats = AXG_TDM_FORMATS, \
|
||||
+}
|
||||
+
|
||||
+#define TOACODEC_INPUT(xname, xid) { \
|
||||
+ .name = xname, \
|
||||
+ .id = (xid), \
|
||||
+ .playback = TOACODEC_STREAM(xname, "Playback", 8), \
|
||||
+ .ops = &g12a_toacodec_input_ops, \
|
||||
+ .probe = meson_codec_glue_input_dai_probe, \
|
||||
+ .remove = meson_codec_glue_input_dai_remove, \
|
||||
+}
|
||||
+
|
||||
+#define TOACODEC_OUTPUT(xname, xid) { \
|
||||
+ .name = xname, \
|
||||
+ .id = (xid), \
|
||||
+ .capture = TOACODEC_STREAM(xname, "Capture", TOACODEC_OUT_CHMAX), \
|
||||
+ .ops = &g12a_toacodec_output_ops, \
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_dai_driver g12a_toacodec_dai_drv[] = {
|
||||
+ TOACODEC_INPUT("I2S IN A", TOACODEC_IN_A),
|
||||
+ TOACODEC_INPUT("I2S IN B", TOACODEC_IN_B),
|
||||
+ TOACODEC_INPUT("I2S IN C", TOACODEC_IN_C),
|
||||
+ TOACODEC_OUTPUT("I2S OUT", TOACODEC_OUT),
|
||||
+};
|
||||
+
|
||||
+static int g12a_toacodec_component_probe(struct snd_soc_component *c)
|
||||
+{
|
||||
+ /* Initialize the static clock parameters */
|
||||
+ return snd_soc_component_write(c, TOACODEC_CTRL0,
|
||||
+ CTRL0_BLK_CAP_INV);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dapm_route g12a_toacodec_routes[] = {
|
||||
+ { "I2S SRC", "I2S A", "I2S IN A Playback" },
|
||||
+ { "I2S SRC", "I2S B", "I2S IN B Playback" },
|
||||
+ { "I2S SRC", "I2S C", "I2S IN C Playback" },
|
||||
+ { "I2S OUT EN", "Switch", "I2S SRC" },
|
||||
+ { "I2S OUT Capture", NULL, "I2S OUT EN" },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_kcontrol_new g12a_toacodec_controls[] = {
|
||||
+ SOC_SINGLE("Lane Select", TOACODEC_CTRL0, CTRL0_LANE_SEL, 3, 0),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver g12a_toacodec_component_drv = {
|
||||
+ .probe = g12a_toacodec_component_probe,
|
||||
+ .controls = g12a_toacodec_controls,
|
||||
+ .num_controls = ARRAY_SIZE(g12a_toacodec_controls),
|
||||
+ .dapm_widgets = g12a_toacodec_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(g12a_toacodec_widgets),
|
||||
+ .dapm_routes = g12a_toacodec_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(g12a_toacodec_routes),
|
||||
+ .endianness = 1,
|
||||
+ .non_legacy_dai_naming = 1,
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config g12a_toacodec_regmap_cfg = {
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+};
|
||||
+
|
||||
+static const struct of_device_id g12a_toacodec_of_match[] = {
|
||||
+ { .compatible = "amlogic,g12a-toacodec", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, g12a_toacodec_of_match);
|
||||
+
|
||||
+static int g12a_toacodec_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ void __iomem *regs;
|
||||
+ struct regmap *map;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = device_reset(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ map = devm_regmap_init_mmio(dev, regs, &g12a_toacodec_regmap_cfg);
|
||||
+ if (IS_ERR(map)) {
|
||||
+ dev_err(dev, "failed to init regmap: %ld\n",
|
||||
+ PTR_ERR(map));
|
||||
+ return PTR_ERR(map);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev,
|
||||
+ &g12a_toacodec_component_drv, g12a_toacodec_dai_drv,
|
||||
+ ARRAY_SIZE(g12a_toacodec_dai_drv));
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver g12a_toacodec_pdrv = {
|
||||
+ .driver = {
|
||||
+ .name = G12A_TOACODEC_DRV_NAME,
|
||||
+ .of_match_table = g12a_toacodec_of_match,
|
||||
+ },
|
||||
+ .probe = g12a_toacodec_probe,
|
||||
+};
|
||||
+module_platform_driver(g12a_toacodec_pdrv);
|
||||
+
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_DESCRIPTION("Amlogic G12a To Internal DAC Codec Driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,27 +0,0 @@
|
||||
From a1388a0e90bc6744e986c73e659b59458782850f Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 14 Aug 2019 17:27:12 +0200
|
||||
Subject: [PATCH 047/146] FROMLIST: ASoC: meson: axg-card: add toacodec support
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/axg-card.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
|
||||
index 372dc696cc8e..48651631bdcf 100644
|
||||
--- a/sound/soc/meson/axg-card.c
|
||||
+++ b/sound/soc/meson/axg-card.c
|
||||
@@ -303,7 +303,8 @@ static int axg_card_cpu_is_tdm_iface(struct device_node *np)
|
||||
|
||||
static int axg_card_cpu_is_codec(struct device_node *np)
|
||||
{
|
||||
- return of_device_is_compatible(np, DT_PREFIX "g12a-tohdmitx");
|
||||
+ return of_device_is_compatible(np, DT_PREFIX "g12a-tohdmitx") ||
|
||||
+ of_device_is_compatible(np, DT_PREFIX "g12a-toacodec");
|
||||
}
|
||||
|
||||
static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,40 +0,0 @@
|
||||
From 824ee4efd64a481515dcd117344d3523a0210f0d Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 25 Feb 2020 06:40:40 +0000
|
||||
Subject: [PATCH 048/146] FROMLIST: arm64: dts: meson: add pdm reset line
|
||||
|
||||
Add the reset line of the PDM device to g12 and sm1 SoCs.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12.dtsi | 1 +
|
||||
arch/arm64/boot/dts/amlogic/meson-sm1.dtsi | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
index 03054c478896..55d39020ec72 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
@@ -56,6 +56,7 @@
|
||||
<&clkc_audio AUD_CLKID_PDM_DCLK>,
|
||||
<&clkc_audio AUD_CLKID_PDM_SYSCLK>;
|
||||
clock-names = "pclk", "dclk", "sysclk";
|
||||
+ resets = <&clkc_audio AUD_RESET_PDM>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
|
||||
index d847a3fcbc85..d4ec735fb1a5 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-sm1.dtsi
|
||||
@@ -448,6 +448,7 @@
|
||||
<&clkc_audio AUD_CLKID_PDM_DCLK>,
|
||||
<&clkc_audio AUD_CLKID_PDM_SYSCLK>;
|
||||
clock-names = "pclk", "dclk", "sysclk";
|
||||
+ resets = <&clkc_audio AUD_RESET_PDM>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From a8441caa5488d1469e570900f74961cf9dd38741 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 25 Feb 2020 06:41:31 +0000
|
||||
Subject: [PATCH 049/146] FROMLIST: arm64: dts: meson: s400: fix sound card
|
||||
codec nodes
|
||||
|
||||
Some codec nodes of the s400 sound card are numbered with the pattern
|
||||
codec@XX. This pattern should be used only if there is a reg property in
|
||||
the node which is not case here. Change this to something acceptable.
|
||||
|
||||
This change is only to better comply with the DT spec. No functional
|
||||
changes expected.
|
||||
|
||||
Fixes: 6f59dc1afbb2 ("arm64: dts: meson-axg: s400: add sound card")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-axg-s400.dts | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
|
||||
index 4cd2d5951822..cb1360ae1211 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts
|
||||
@@ -313,15 +313,15 @@
|
||||
dai-tdm-slot-rx-mask-1 = <1 1>;
|
||||
mclk-fs = <256>;
|
||||
|
||||
- codec@0 {
|
||||
+ codec-0 {
|
||||
sound-dai = <&lineout>;
|
||||
};
|
||||
|
||||
- codec@1 {
|
||||
+ codec-1 {
|
||||
sound-dai = <&speaker_amp1>;
|
||||
};
|
||||
|
||||
- codec@2 {
|
||||
+ codec-2 {
|
||||
sound-dai = <&linein>;
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 70ceabe05241b93db594e77de60cd9dc7a48269d Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 25 Feb 2020 06:42:20 +0000
|
||||
Subject: [PATCH 050/146] FROMLIST: arm64: dts: meson: sei510: fix sound card
|
||||
codec node
|
||||
|
||||
A codec node of the sei510 sound card is numbered with the pattern
|
||||
codec@XX. This pattern should be used only if there is a reg property in
|
||||
the node which is not case here. Change this to something acceptable.
|
||||
|
||||
This change is only to better comply with the DT spec. No functional
|
||||
changes expected.
|
||||
|
||||
Fixes: 64c10554bf9c ("arm64: dts: meson: sei510: add sound card")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
|
||||
index 2ac9e3a43b96..168f460e11fa 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts
|
||||
@@ -269,7 +269,7 @@
|
||||
dai-tdm-slot-tx-mask-3 = <1 1>;
|
||||
mclk-fs = <256>;
|
||||
|
||||
- codec@0 {
|
||||
+ codec {
|
||||
sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
|
||||
};
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,26 +0,0 @@
|
||||
From 8f207ceb43f354e6da4074b38e7e37c7ea496bea Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 4 Dec 2019 17:09:06 +0100
|
||||
Subject: [PATCH 051/146] WIP: arm64: defconfig: enable meson gx audio as
|
||||
module
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/configs/defconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
|
||||
index 905109f6814f..ccc7f6313ef8 100644
|
||||
--- a/arch/arm64/configs/defconfig
|
||||
+++ b/arch/arm64/configs/defconfig
|
||||
@@ -581,6 +581,7 @@ CONFIG_SND_HDA_CODEC_HDMI=m
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_BCM2835_SOC_I2S=m
|
||||
CONFIG_SND_MESON_AXG_SOUND_CARD=m
|
||||
+CONFIG_SND_MESON_GX_SOUND_CARD=m
|
||||
CONFIG_SND_SOC_ROCKCHIP=m
|
||||
CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
|
||||
CONFIG_SND_SOC_ROCKCHIP_RT5645=m
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,110 +0,0 @@
|
||||
From 779a94302dd774eafa43a9743bebee684308c02b Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 14 Aug 2019 17:28:36 +0200
|
||||
Subject: [PATCH 053/146] WIP: arm64: dts: meson: g12a: add internal DAC glue
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12.dtsi | 9 +++++
|
||||
sound/soc/meson/g12a-toacodec.c | 42 ++++++++++++++--------
|
||||
2 files changed, 36 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
index 55d39020ec72..0d14409f509c 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12.dtsi
|
||||
@@ -343,6 +343,15 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
+ toacodec: audio-controller@740 {
|
||||
+ compatible = "amlogic,g12a-toacodec";
|
||||
+ reg = <0x0 0x740 0x0 0x4>;
|
||||
+ #sound-dai-cells = <1>;
|
||||
+ sound-name-prefix = "TOACODEC";
|
||||
+ resets = <&clkc_audio AUD_RESET_TOACODEC>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
tohdmitx: audio-controller@744 {
|
||||
compatible = "amlogic,g12a-tohdmitx";
|
||||
reg = <0x0 0x744 0x0 0x4>;
|
||||
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
|
||||
index 0ee074f6fc87..4e29528a8cb4 100644
|
||||
--- a/sound/soc/meson/g12a-toacodec.c
|
||||
+++ b/sound/soc/meson/g12a-toacodec.c
|
||||
@@ -21,7 +21,8 @@
|
||||
|
||||
#define TOACODEC_CTRL0 0x0
|
||||
#define CTRL0_ENABLE_SHIFT 31
|
||||
-#define CTRL0_DAT_SEL GENMASK(15, 14)
|
||||
+#define CTRL0_DAT_SEL_SHIFT 14
|
||||
+#define CTRL0_DAT_SEL (0x3 << CTRL0_DAT_SEL_SHIFT)
|
||||
#define CTRL0_LANE_SEL 12
|
||||
#define CTRL0_LRCLK_SEL GENMASK(9, 8)
|
||||
#define CTRL0_BLK_CAP_INV BIT(7)
|
||||
@@ -35,18 +36,28 @@ static const char * const g12a_toacodec_mux_texts[] = {
|
||||
"I2S A", "I2S B", "I2S C",
|
||||
};
|
||||
|
||||
-static int g12a_toacodec_get_mux(struct snd_soc_component *component)
|
||||
+static int g12a_toacodec_mux_put_enum(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
- unsigned int val;
|
||||
+ struct snd_soc_component *component =
|
||||
+ snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
+ struct snd_soc_dapm_context *dapm =
|
||||
+ snd_soc_dapm_kcontrol_dapm(kcontrol);
|
||||
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
+ unsigned int mux, changed;
|
||||
|
||||
- snd_soc_component_read(component, TOACODEC_CTRL0, &val);
|
||||
- return FIELD_GET(CTRL0_DAT_SEL, val);
|
||||
-}
|
||||
+ mux = snd_soc_enum_item_to_val(e, ucontrol->value.enumerated.item[0]);
|
||||
+ changed = snd_soc_component_test_bits(component, e->reg,
|
||||
+ CTRL0_DAT_SEL,
|
||||
+ FIELD_PREP(CTRL0_DAT_SEL, mux));
|
||||
|
||||
-static int g12a_toacodec_put_mux(struct snd_soc_component *component,
|
||||
- unsigned int mux)
|
||||
-{
|
||||
- snd_soc_component_update_bits(component, TOACODEC_CTRL0,
|
||||
+ if (!changed)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* Force disconnect of the mux while updating */
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL);
|
||||
+
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
CTRL0_DAT_SEL |
|
||||
CTRL0_LRCLK_SEL |
|
||||
CTRL0_BCLK_SEL,
|
||||
@@ -65,17 +76,18 @@ static int g12a_toacodec_put_mux(struct snd_soc_component *component,
|
||||
* source. For that, we will need regmap backed clock mux which
|
||||
* is a work in progress
|
||||
*/
|
||||
- snd_soc_component_update_bits(component, TOACODEC_CTRL0,
|
||||
+ snd_soc_component_update_bits(component, e->reg,
|
||||
CTRL0_MCLK_SEL,
|
||||
FIELD_PREP(CTRL0_MCLK_SEL, mux));
|
||||
|
||||
+ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static MESON_CODEC_GLUE_ENUM_DECL(g12a_toacodec_mux_glue,
|
||||
- g12a_toacodec_mux_texts,
|
||||
- g12a_toacodec_get_mux,
|
||||
- g12a_toacodec_put_mux);
|
||||
+static SOC_ENUM_SINGLE_DECL(g12a_toacodec_mux_enum, TOACODEC_CTRL0,
|
||||
+ CTRL0_DAT_SEL_SHIFT,
|
||||
+ g12a_toacodec_mux_texts);
|
||||
|
||||
static const struct snd_kcontrol_new g12a_toacodec_mux =
|
||||
SOC_DAPM_ENUM_EXT("Source", g12a_toacodec_mux_enum,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,351 +0,0 @@
|
||||
From 85599505da66a3e8fc0b16653d3bec82c21f2c79 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 18 Mar 2019 13:46:06 +0100
|
||||
Subject: [PATCH 054/146] WIP: arm64: dts: meson: u200: add audio support
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-g12a-u200.dts | 292 ++++++++++++++++++
|
||||
1 file changed, 292 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
|
||||
index 2a324f0136e3..0dc2476185c0 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "meson-g12a.dtsi"
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/gpio/meson-g12a-gpio.h>
|
||||
+#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
|
||||
+#include <dt-bindings/sound/meson-g12a-toacodec.h>
|
||||
|
||||
/ {
|
||||
compatible = "amlogic,u200", "amlogic,g12a";
|
||||
@@ -18,6 +20,20 @@
|
||||
ethernet0 = ðmac;
|
||||
};
|
||||
|
||||
+ dioo2133: audio-amplifier-0 {
|
||||
+ compatible = "simple-audio-amplifier";
|
||||
+ enable-gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>;
|
||||
+ VCC-supply = <&vcc_5v>;
|
||||
+ sound-name-prefix = "10U2";
|
||||
+ };
|
||||
+
|
||||
+ spdif_dit: audio-codec-1 {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "linux,spdif-dit";
|
||||
+ status = "okay";
|
||||
+ sound-name-prefix = "DIT";
|
||||
+ };
|
||||
+
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
@@ -147,6 +163,182 @@
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "amlogic,axg-sound-card";
|
||||
+ model = "G12A-U200";
|
||||
+ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>,
|
||||
+ <&tdmin_a>, <&tdmin_b>, <&tdmin_c>,
|
||||
+ <&tdmin_lb>, <&dioo2133>;
|
||||
+ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0",
|
||||
+ "TDMOUT_A IN 1", "FRDDR_B OUT 0",
|
||||
+ "TDMOUT_A IN 2", "FRDDR_C OUT 0",
|
||||
+ "TDM_A Playback", "TDMOUT_A OUT",
|
||||
+ "TDMOUT_B IN 0", "FRDDR_A OUT 1",
|
||||
+ "TDMOUT_B IN 1", "FRDDR_B OUT 1",
|
||||
+ "TDMOUT_B IN 2", "FRDDR_C OUT 1",
|
||||
+ "TDM_B Playback", "TDMOUT_B OUT",
|
||||
+ "TDMOUT_C IN 0", "FRDDR_A OUT 2",
|
||||
+ "TDMOUT_C IN 1", "FRDDR_B OUT 2",
|
||||
+ "TDMOUT_C IN 2", "FRDDR_C OUT 2",
|
||||
+ "TDM_C Playback", "TDMOUT_C OUT",
|
||||
+ "SPDIFOUT IN 0", "FRDDR_A OUT 3",
|
||||
+ "SPDIFOUT IN 1", "FRDDR_B OUT 3",
|
||||
+ "SPDIFOUT IN 2", "FRDDR_C OUT 3",
|
||||
+ "TDMIN_A IN 0", "TDM_A Capture",
|
||||
+ "TDMIN_A IN 1", "TDM_B Capture",
|
||||
+ "TDMIN_A IN 3", "TDM_A Loopback",
|
||||
+ "TDMIN_A IN 4", "TDM_B Loopback",
|
||||
+ "TDMIN_B IN 0", "TDM_A Capture",
|
||||
+ "TDMIN_B IN 1", "TDM_B Capture",
|
||||
+ "TDMIN_B IN 3", "TDM_A Loopback",
|
||||
+ "TDMIN_B IN 4", "TDM_B Loopback",
|
||||
+ "TDMIN_C IN 0", "TDM_A Capture",
|
||||
+ "TDMIN_C IN 1", "TDM_B Capture",
|
||||
+ "TDMIN_C IN 3", "TDM_A Loopback",
|
||||
+ "TDMIN_C IN 4", "TDM_B Loopback",
|
||||
+ "TDMIN_LB IN 3", "TDM_A Capture",
|
||||
+ "TDMIN_LB IN 4", "TDM_B Capture",
|
||||
+ "TDMIN_LB IN 0", "TDM_A Loopback",
|
||||
+ "TDMIN_LB IN 1", "TDM_B Loopback",
|
||||
+ "TODDR_A IN 0", "TDMIN_A OUT",
|
||||
+ "TODDR_B IN 0", "TDMIN_A OUT",
|
||||
+ "TODDR_C IN 0", "TDMIN_A OUT",
|
||||
+ "TODDR_A IN 1", "TDMIN_B OUT",
|
||||
+ "TODDR_B IN 1", "TDMIN_B OUT",
|
||||
+ "TODDR_C IN 1", "TDMIN_B OUT",
|
||||
+ "TODDR_A IN 2", "TDMIN_C OUT",
|
||||
+ "TODDR_B IN 2", "TDMIN_C OUT",
|
||||
+ "TODDR_C IN 2", "TDMIN_C OUT",
|
||||
+ "TODDR_A IN 6", "TDMIN_LB OUT",
|
||||
+ "TODDR_B IN 6", "TDMIN_LB OUT",
|
||||
+ "TODDR_C IN 6", "TDMIN_LB OUT",
|
||||
+ "10U2 INL", "ACODEC LOLP",
|
||||
+ "10U2 INR", "ACODEC LORP";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_HIFI_PLL>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <589824000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ status = "okay";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&frddr_a>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&frddr_b>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-2 {
|
||||
+ sound-dai = <&frddr_c>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-3 {
|
||||
+ sound-dai = <&toddr_a>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-4 {
|
||||
+ sound-dai = <&toddr_b>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-5 {
|
||||
+ sound-dai = <&toddr_c>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-6 {
|
||||
+ sound-dai = <&tdmif_b>;
|
||||
+ dai-format = "i2s";
|
||||
+ dai-tdm-slot-tx-mask-0 = <1 1>;
|
||||
+ mclk-fs = <256>;
|
||||
+
|
||||
+ codec@0 {
|
||||
+ sound-dai = <&toacodec TOACODEC_IN_B>;
|
||||
+ };
|
||||
+
|
||||
+ codec@1 {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-7 {
|
||||
+ sound-dai = <&tdmif_a>;
|
||||
+ dai-format = "i2s";
|
||||
+ dai-tdm-slot-tx-mask-0 = <1 1>;
|
||||
+ mclk-fs = <256>;
|
||||
+
|
||||
+ codec@0 {
|
||||
+ sound-dai = <&toacodec TOACODEC_IN_A>;
|
||||
+ };
|
||||
+
|
||||
+ codec@1 {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-8 {
|
||||
+ sound-dai = <&tdmif_c>;
|
||||
+ dai-format = "i2s";
|
||||
+ dai-tdm-slot-tx-mask-0 = <1 1>;
|
||||
+ mclk-fs = <256>;
|
||||
+
|
||||
+ codec@0 {
|
||||
+ sound-dai = <&toacodec TOACODEC_IN_C>;
|
||||
+ };
|
||||
+
|
||||
+ codec@1 {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-9 {
|
||||
+ sound-dai = <&spdifout>;
|
||||
+
|
||||
+ codec@0 {
|
||||
+ sound-dai = <&spdif_dit>;
|
||||
+ };
|
||||
+
|
||||
+ codec@1 {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_A>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-10 {
|
||||
+ sound-dai = <&spdifout_b>;
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_SPDIF_IN_B>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-11 {
|
||||
+ sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-12 {
|
||||
+ sound-dai = <&toacodec TOACODEC_OUT>;
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&acodec>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&acodec {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&arb {
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -191,6 +383,10 @@
|
||||
clock-latency = <50000>;
|
||||
};
|
||||
|
||||
+&clkc_audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -203,6 +399,18 @@
|
||||
phy-mode = "rmii";
|
||||
};
|
||||
|
||||
+&frddr_a {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&frddr_b {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&frddr_c {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>;
|
||||
@@ -288,6 +496,90 @@
|
||||
vqmmc-supply = <&flash_1v8>;
|
||||
};
|
||||
|
||||
+&spdifout {
|
||||
+ pinctrl-0 = <&spdif_ao_out_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&spdifout_b {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmif_a {
|
||||
+ pinctrl-0 = <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>, <&tdm_a_dout0_pins> ;
|
||||
+ pinctrl-names = "default";
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmif_b {
|
||||
+ pinctrl-0 = <&mclk0_a_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>,
|
||||
+ <&tdm_b_dout0_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ status = "okay";
|
||||
+
|
||||
+ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_MCLK_PAD0>,
|
||||
+ <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>,
|
||||
+ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>;
|
||||
+ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_MCLK>,
|
||||
+ <&clkc_audio AUD_CLKID_MST_B_SCLK>,
|
||||
+ <&clkc_audio AUD_CLKID_MST_B_LRCLK>;
|
||||
+ assigned-clock-rates = <0>, <0>, <0>;
|
||||
+};
|
||||
+
|
||||
+&tdmif_c {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmin_a {
|
||||
+ inctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmin_b {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmin_c {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmin_lb {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmout_a {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmout_b {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tdmout_c {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&toacodec {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&toddr_a {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&toddr_b {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&toddr_c {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&tohdmitx {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&uart_AO {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&uart_ao_a_pins>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,99 +0,0 @@
|
||||
From defec385aa0888d28eabba06d625fb3104c0917a Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 22 Oct 2019 18:15:43 +0200
|
||||
Subject: [PATCH 055/146] WIP: arm64: dts: meson-gx: add playback audio devices
|
||||
|
||||
FIXME: Missing gxbb ATM
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 34 ++++++++++++++++++++++
|
||||
2 files changed, 47 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index 40db06e28b66..962a56e0e8b4 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -226,6 +226,17 @@
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
+ aiu: audio-controller@5400 {
|
||||
+ compatible = "amlogic,aiu";
|
||||
+ #sound-dai-cells = <2>;
|
||||
+ sound-name-prefix = "AIU";
|
||||
+ reg = <0x0 0x5400 0x0 0x2ac>;
|
||||
+ interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>,
|
||||
+ <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
|
||||
+ interrupt-names = "i2s", "spdif";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
uart_A: serial@84c0 {
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x0 0x84c0 0x0 0x18>;
|
||||
@@ -574,6 +585,8 @@
|
||||
interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ sound-name-prefix = "HDMITX";
|
||||
status = "disabled";
|
||||
|
||||
/* VPU VENC Input */
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index 259d86399390..ec50e93470f9 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -14,6 +14,17 @@
|
||||
compatible = "amlogic,meson-gxl";
|
||||
|
||||
soc {
|
||||
+ acodec: audio-controller@c8832000 {
|
||||
+ compatible = "amlogic,t9015";
|
||||
+ reg = <0x0 0xc8832000 0x0 0x14>;
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ sound-name-prefix = "ACODEC";
|
||||
+ clocks = <&clkc CLKID_ACODEC>;
|
||||
+ clock-names = "pclk";
|
||||
+ resets = <&reset RESET_ACODEC>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
usb0: usb@c9000000 {
|
||||
status = "disabled";
|
||||
compatible = "amlogic,meson-gxl-dwc3";
|
||||
@@ -49,6 +60,29 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&aiu {
|
||||
+ compatible = "amlogic,aiu-gxl", "amlogic,aiu";
|
||||
+ clocks = <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "pclk",
|
||||
+ "i2s_pclk",
|
||||
+ "i2s_aoclk",
|
||||
+ "i2s_mclk",
|
||||
+ "i2s_mixer",
|
||||
+ "spdif_pclk",
|
||||
+ "spdif_aoclk",
|
||||
+ "spdif_mclk",
|
||||
+ "spdif_mclk_sel";
|
||||
+ resets = <&reset RESET_AIU>;
|
||||
+};
|
||||
+
|
||||
&apb {
|
||||
usb2_phy0: phy@78000 {
|
||||
compatible = "amlogic,meson-gxl-usb2-phy";
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,127 +0,0 @@
|
||||
From 75ba992dc1dfd9a186c71c92741e26bdd4043117 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 17 Dec 2019 11:05:36 +0100
|
||||
Subject: [PATCH 059/146] WIP: arm64: dts: meson: add sound support to the
|
||||
libretech-pc
|
||||
|
||||
Add HDMI sound support on the libretech PC form factor
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
.../dts/amlogic/meson-gx-libretech-pc.dtsi | 79 +++++++++++++++++++
|
||||
1 file changed, 79 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-libretech-pc.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-libretech-pc.dtsi
|
||||
index 248b018c83d5..c8a1d97f146d 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx-libretech-pc.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-libretech-pc.dtsi
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
|
||||
/ {
|
||||
adc-keys {
|
||||
@@ -29,6 +30,13 @@
|
||||
spi0 = &spifc;
|
||||
};
|
||||
|
||||
+ dio2133: analog-amplifier {
|
||||
+ compatible = "simple-audio-amplifier";
|
||||
+ sound-name-prefix = "AU2";
|
||||
+ VCC-supply = <&vcc5v>;
|
||||
+ enable-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
@@ -175,6 +183,69 @@
|
||||
regulator-settling-time-up-us = <200>;
|
||||
regulator-settling-time-down-us = <50000>;
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "amlogic,gx-sound-card";
|
||||
+ model = "GXL-LIBRETECH-S9XX-PC";
|
||||
+ audio-aux-devs = <&dio2133>;
|
||||
+ audio-widgets = "Speaker", "7J4-14 LEFT",
|
||||
+ "Speaker", "7J4-11 RIGHT";
|
||||
+ audio-routing = "AU2 INL", "ACODEC LOLN",
|
||||
+ "AU2 INR", "ACODEC LORN",
|
||||
+ "7J4-14 LEFT", "AU2 OUTL",
|
||||
+ "7J4-11 RIGHT", "AU2 OUTR";
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>;
|
||||
+ dai-format = "i2s";
|
||||
+ mclk-fs = <512>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_I2S>;
|
||||
+ };
|
||||
+
|
||||
+ codec-1 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_I2S>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-2 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-3 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&acodec>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&acodec {
|
||||
+ AVDD-supply = <&vddio_ao18>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu {
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -211,6 +282,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&acodec {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&pinctrl_periphs {
|
||||
/*
|
||||
* Make sure the reset pin of the usb HUB is driven high to take
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,109 +0,0 @@
|
||||
From 0fad7c2ff463b25f36a817f76733103b292368a4 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Wed, 19 Feb 2020 04:27:30 +0000
|
||||
Subject: [PATCH 061/146] WIP: arm64: dts: meson: add audio playback to khadas
|
||||
vim2
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
.../dts/amlogic/meson-gxm-khadas-vim2.dts | 70 +++++++++++++++++++
|
||||
1 file changed, 70 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
index f82f25c1a5f9..a25786c68def 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
@@ -8,6 +8,7 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/input/input.h>
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
#include <dt-bindings/thermal/thermal.h>
|
||||
|
||||
#include "meson-gxm.dtsi"
|
||||
@@ -25,6 +26,13 @@
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
+ dio2133: analog-amplifier {
|
||||
+ compatible = "simple-audio-amplifier";
|
||||
+ sound-name-prefix = "AU2";
|
||||
+ VCC-supply = <&hdmi_5v>;
|
||||
+ enable-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x0 0x0 0x80000000>;
|
||||
@@ -189,6 +197,68 @@
|
||||
clock-frequency = <32768>;
|
||||
pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "amlogic,gx-sound-card";
|
||||
+ model = "GXM-KHADAS-VIM2";
|
||||
+ audio-aux-devs = <&dio2133>;
|
||||
+ audio-widgets = "Line", "Lineout";
|
||||
+ audio-routing = "AU2 INL", "ACODEC LOLN",
|
||||
+ "AU2 INR", "ACODEC LORN",
|
||||
+ "Lineout", "AU2 OUTL",
|
||||
+ "Lineout", "AU2 OUTR";
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>;
|
||||
+ dai-format = "i2s";
|
||||
+ mclk-fs = <512>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_I2S>;
|
||||
+ };
|
||||
+
|
||||
+ codec-1 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_I2S>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-2 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-3 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&acodec>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&acodec {
|
||||
+ AVDD-supply = <&vddio_ao18>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu {
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,48 +0,0 @@
|
||||
From f8c9f131746fbb1d1e595677b341fcbdace84fd3 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Tue, 18 Feb 2020 12:23:31 +0000
|
||||
Subject: [PATCH 062/146] WIP: arm64: dts: meson-gxbb: add playback audio
|
||||
devices
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 23 +++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 0cb40326b0d3..ccaa1a8e28c5 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -241,6 +241,29 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&aiu {
|
||||
+ compatible = "amlogic,aiu-gxbb", "amlogic,aiu";
|
||||
+ clocks = <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "pclk",
|
||||
+ "i2s_pclk",
|
||||
+ "i2s_aoclk",
|
||||
+ "i2s_mclk",
|
||||
+ "i2s_mixer",
|
||||
+ "spdif_pclk",
|
||||
+ "spdif_aoclk",
|
||||
+ "spdif_mclk",
|
||||
+ "spdif_mclk_sel";
|
||||
+ resets = <&reset RESET_AIU>;
|
||||
+};
|
||||
+
|
||||
&apb {
|
||||
mali: gpu@c0000 {
|
||||
compatible = "amlogic,meson-gxbb-mali", "arm,mali-450";
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,90 +0,0 @@
|
||||
From d532a10ddc137630f270abc54a49432eb1dcf05c Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Wed, 19 Feb 2020 11:12:18 +0000
|
||||
Subject: [PATCH 065/146] WIP: arm64: dts: meson: add audio playback to p20x
|
||||
dtsi
|
||||
|
||||
Signed-off-by: chewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gxbb-p20x.dtsi | 58 +++++++++++++++++++
|
||||
1 file changed, 58 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
index e803a466fe4e..1c428f9d6039 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "meson-gxbb.dtsi"
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
@@ -113,6 +114,63 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+
|
||||
+ spdif_dit: audio-codec-0 {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "linux,spdif-dit";
|
||||
+ status = "okay";
|
||||
+ sound-name-prefix = "DIT";
|
||||
+ };
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "amlogic,gx-sound-card";
|
||||
+ model = "GXBB-P20X";
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>;
|
||||
+ dai-format = "i2s";
|
||||
+ mclk-fs = <512>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_I2S>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-2 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_SPDIF_ENCODER>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&spdif_dit>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-3 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&aiu {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&spdif_out_y_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 91500a871db490d0f1b0be10cb1481c06d096234 Mon Sep 17 00:00:00 2001
|
||||
From: chewitt <christianshewitt@gmail.com>
|
||||
Date: Tue, 24 Dec 2019 05:50:45 +0000
|
||||
Subject: [PATCH 071/146] HACK: mmc: meson-gx: force max_segs/max_blk_count
|
||||
values in dram access quirk
|
||||
|
||||
Temporary workaround for the G12A and G12B SDIO chip bug that causes sdio
|
||||
issues with brcmfmac. Patch is based on [1] by @hyphop (Khadas) and hints
|
||||
from @superna9999.
|
||||
|
||||
[1] https://github.com/hyphop/khadas-linux-kernel/blob/master/patches/linux-5.4.5/0005-VIM3_wifi_hack.patch
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
drivers/mmc/host/meson-gx-mmc.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
|
||||
index 35400cf2a2e4..a49f63791b0e 100644
|
||||
--- a/drivers/mmc/host/meson-gx-mmc.c
|
||||
+++ b/drivers/mmc/host/meson-gx-mmc.c
|
||||
@@ -1144,8 +1144,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
||||
mmc->caps |= MMC_CAP_CMD23;
|
||||
if (host->dram_access_quirk) {
|
||||
/* Limit to the available sram memory */
|
||||
- mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
|
||||
- mmc->max_blk_count = mmc->max_segs;
|
||||
+ //mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size;
|
||||
+ //mmc->max_blk_count = mmc->max_segs;
|
||||
+ mmc->max_segs = 1;
|
||||
+ mmc->max_blk_count = 2;
|
||||
} else {
|
||||
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
|
||||
mmc->max_segs = SD_EMMC_DESC_BUF_LEN /
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,164 +0,0 @@
|
||||
From e78d4dc4e45bbc6cb77c9c16ffb06c25a7bbbe17 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Vavro <afl2001@gmail.com>
|
||||
Date: Sat, 10 Aug 2019 13:55:34 +0000
|
||||
Subject: [PATCH 075/146] FROMLIST: pinctrl: meson: add missing tsin pinctrl
|
||||
for meson gxbb/gxl
|
||||
|
||||
This patch adds missing tsin pinctrl definitions for meson gxbb and gxl/gxm
|
||||
|
||||
Signed-off-by: Igor Vavro <afl2001@gmail.com>
|
||||
---
|
||||
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 43 ++++++++++++++++++++--
|
||||
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 27 ++++++++++++++
|
||||
2 files changed, 66 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
|
||||
index 926b9997159a..25325235d82f 100644
|
||||
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
|
||||
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
|
||||
@@ -231,10 +231,24 @@ static const unsigned int hdmi_hpd_pins[] = { GPIOH_0 };
|
||||
static const unsigned int hdmi_sda_pins[] = { GPIOH_1 };
|
||||
static const unsigned int hdmi_scl_pins[] = { GPIOH_2 };
|
||||
|
||||
+static const unsigned int tsin_a_d_valid_pins[] = { GPIOY_0 };
|
||||
+static const unsigned int tsin_a_sop_pins[] = { GPIOY_1 };
|
||||
+static const unsigned int tsin_a_clk_pins[] = { GPIOY_2 };
|
||||
+static const unsigned int tsin_a_d0_pins[] = { GPIOY_3 };
|
||||
+static const unsigned int tsin_a_dp_pins[] = {
|
||||
+ GPIOY_4, GPIOY_5, GPIOY_6, GPIOY_7, GPIOY_8, GPIOY_9, GPIOY_10
|
||||
+};
|
||||
+
|
||||
+static const unsigned int tsin_a_fail_pins[] = { GPIOY_11 };
|
||||
static const unsigned int i2s_out_ch23_y_pins[] = { GPIOY_8 };
|
||||
static const unsigned int i2s_out_ch45_y_pins[] = { GPIOY_9 };
|
||||
static const unsigned int i2s_out_ch67_y_pins[] = { GPIOY_10 };
|
||||
|
||||
+static const unsigned int tsin_b_d_valid_pins[] = { GPIOX_6 };
|
||||
+static const unsigned int tsin_b_sop_pins[] = { GPIOX_7 };
|
||||
+static const unsigned int tsin_b_clk_pins[] = { GPIOX_8 };
|
||||
+static const unsigned int tsin_b_d0_pins[] = { GPIOX_9 };
|
||||
+
|
||||
static const unsigned int spdif_out_y_pins[] = { GPIOY_12 };
|
||||
|
||||
static const unsigned int gen_clk_out_pins[] = { GPIOY_15 };
|
||||
@@ -437,12 +451,22 @@ static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
|
||||
GROUP(pwm_a_x, 3, 17),
|
||||
GROUP(pwm_e, 2, 30),
|
||||
GROUP(pwm_f_x, 3, 18),
|
||||
+ GROUP(tsin_b_d_valid, 3, 9),
|
||||
+ GROUP(tsin_b_sop, 3, 8),
|
||||
+ GROUP(tsin_b_clk, 3, 10),
|
||||
+ GROUP(tsin_b_d0, 3, 7),
|
||||
|
||||
/* Bank Y */
|
||||
- GROUP(uart_cts_c, 1, 17),
|
||||
- GROUP(uart_rts_c, 1, 16),
|
||||
- GROUP(uart_tx_c, 1, 19),
|
||||
- GROUP(uart_rx_c, 1, 18),
|
||||
+ GROUP(tsin_a_fail, 3, 3),
|
||||
+ GROUP(tsin_a_d_valid, 3, 2),
|
||||
+ GROUP(tsin_a_sop, 3, 1),
|
||||
+ GROUP(tsin_a_clk, 3, 0),
|
||||
+ GROUP(tsin_a_d0, 3, 4),
|
||||
+ GROUP(tsin_a_dp, 3, 5),
|
||||
+ GROUP(uart_cts_c, 1, 19),
|
||||
+ GROUP(uart_rts_c, 1, 18),
|
||||
+ GROUP(uart_tx_c, 1, 17),
|
||||
+ GROUP(uart_rx_c, 1, 16),
|
||||
GROUP(pwm_a_y, 1, 21),
|
||||
GROUP(pwm_f_y, 1, 20),
|
||||
GROUP(i2s_out_ch23_y, 1, 5),
|
||||
@@ -601,6 +625,15 @@ static const char * const gpio_periphs_groups[] = {
|
||||
"GPIOX_20", "GPIOX_21", "GPIOX_22",
|
||||
};
|
||||
|
||||
+static const char * const tsin_a_groups[] = {
|
||||
+ "tsin_a_clk", "tsin_a_sop", "tsin_a_d_valid", "tsin_a_d0",
|
||||
+ "tsin_a_dp", "tsin_a_fail",
|
||||
+};
|
||||
+
|
||||
+static const char * const tsin_b_groups[] = {
|
||||
+ "tsin_b_clk", "tsin_b_sop", "tsin_b_d_valid", "tsin_b_d0",
|
||||
+};
|
||||
+
|
||||
static const char * const emmc_groups[] = {
|
||||
"emmc_nand_d07", "emmc_clk", "emmc_cmd", "emmc_ds",
|
||||
};
|
||||
@@ -792,6 +825,8 @@ static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
|
||||
FUNCTION(i2s_out),
|
||||
FUNCTION(spdif_out),
|
||||
FUNCTION(gen_clk_out),
|
||||
+ FUNCTION(tsin_a),
|
||||
+ FUNCTION(tsin_b),
|
||||
};
|
||||
|
||||
static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
|
||||
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
|
||||
index 1b6e8646700f..45d58311db27 100644
|
||||
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
|
||||
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
|
||||
@@ -241,6 +241,17 @@ static const unsigned int tsin_a_dp_pins[] = {
|
||||
GPIODV_1, GPIODV_2, GPIODV_3, GPIODV_4, GPIODV_5, GPIODV_6, GPIODV_7,
|
||||
};
|
||||
|
||||
+static const unsigned int tsin_b_clk_pins[] = { GPIOH_6 };
|
||||
+static const unsigned int tsin_b_d0_pins[] = { GPIOH_7 };
|
||||
+static const unsigned int tsin_b_sop_pins[] = { GPIOH_8 };
|
||||
+static const unsigned int tsin_b_d_valid_pins[] = { GPIOH_9 };
|
||||
+
|
||||
+static const unsigned int tsin_b_fail_z4_pins[] = { GPIOZ_4 };
|
||||
+static const unsigned int tsin_b_clk_z3_pins[] = { GPIOZ_3 };
|
||||
+static const unsigned int tsin_b_d0_z2_pins[] = { GPIOZ_2 };
|
||||
+static const unsigned int tsin_b_sop_z1_pins[] = { GPIOZ_1 };
|
||||
+static const unsigned int tsin_b_d_valid_z0_pins[] = { GPIOZ_0 };
|
||||
+
|
||||
static const struct pinctrl_pin_desc meson_gxl_aobus_pins[] = {
|
||||
MESON_PIN(GPIOAO_0),
|
||||
MESON_PIN(GPIOAO_1),
|
||||
@@ -438,6 +449,11 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = {
|
||||
GROUP(eth_txd1, 4, 12),
|
||||
GROUP(eth_txd2, 4, 11),
|
||||
GROUP(eth_txd3, 4, 10),
|
||||
+ GROUP(tsin_b_fail_z4, 3, 15),
|
||||
+ GROUP(tsin_b_clk_z3, 3, 16),
|
||||
+ GROUP(tsin_b_d0_z2, 3, 17),
|
||||
+ GROUP(tsin_b_sop_z1, 3, 18),
|
||||
+ GROUP(tsin_b_d_valid_z0, 3, 19),
|
||||
GROUP(pwm_c, 3, 20),
|
||||
GROUP(i2s_out_ch23_z, 3, 26),
|
||||
GROUP(i2s_out_ch45_z, 3, 25),
|
||||
@@ -454,6 +470,10 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = {
|
||||
GROUP(i2s_out_lr_clk, 6, 24),
|
||||
GROUP(i2s_out_ch01, 6, 23),
|
||||
GROUP(spdif_out_h, 6, 28),
|
||||
+ GROUP(tsin_b_d0, 6, 17),
|
||||
+ GROUP(tsin_b_sop, 6, 18),
|
||||
+ GROUP(tsin_b_d_valid, 6, 19),
|
||||
+ GROUP(tsin_b_clk, 6, 20),
|
||||
|
||||
/* Bank DV */
|
||||
GROUP(uart_tx_b, 2, 16),
|
||||
@@ -689,6 +709,12 @@ static const char * const tsin_a_groups[] = {
|
||||
"tsin_a_dp", "tsin_a_fail",
|
||||
};
|
||||
|
||||
+static const char * const tsin_b_groups[] = {
|
||||
+ "tsin_b_clk", "tsin_b_sop", "tsin_b_d_valid", "tsin_b_d0",
|
||||
+ "tsin_b_clk_z3", "tsin_b_sop_z1", "tsin_b_d_valid_z0", "tsin_b_d0_z2",
|
||||
+ "tsin_b_fail_z4",
|
||||
+};
|
||||
+
|
||||
static const char * const gpio_aobus_groups[] = {
|
||||
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
|
||||
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
|
||||
@@ -764,6 +790,7 @@ static struct meson_pmx_func meson_gxl_periphs_functions[] = {
|
||||
FUNCTION(spdif_out),
|
||||
FUNCTION(eth_led),
|
||||
FUNCTION(tsin_a),
|
||||
+ FUNCTION(tsin_b),
|
||||
};
|
||||
|
||||
static struct meson_pmx_func meson_gxl_aobus_functions[] = {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,34 +0,0 @@
|
||||
From ad6f8481a1aec44752921c6a45f5703ae5caed00 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 17 Oct 2019 21:03:22 +0000
|
||||
Subject: [PATCH 076/146] FROMLIST: doc: dt: bindings: usb: dwc3: Update
|
||||
entries for disabling SS instances in park mode
|
||||
|
||||
This patch updates the documentation with the information related
|
||||
to the quirks that needs to be added for disabling all SuperSpeed XHCi
|
||||
instances in park mode.
|
||||
|
||||
CC: Dongjin Kim <tobetter@gmail.com>
|
||||
Cc: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Reported-by: Tim <elatllat@gmail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
|
||||
index 66780a47ad85..c977a3ba2f35 100644
|
||||
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
|
||||
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
|
||||
@@ -75,6 +75,8 @@ Optional properties:
|
||||
from P0 to P1/P2/P3 without delay.
|
||||
- snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
|
||||
during HS transmit.
|
||||
+ - snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in
|
||||
+ park mode are disabled.
|
||||
- snps,dis_metastability_quirk: when set, disable metastability workaround.
|
||||
CAUTION: use only if you are absolutely sure of it.
|
||||
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,85 +0,0 @@
|
||||
From aee4900b43ffcc9641d0f16199294f6631d97e22 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 17 Oct 2019 21:04:34 +0000
|
||||
Subject: [PATCH 077/146] FROMLIST: usb: dwc3: gadget: Add support for
|
||||
disabling SS instances in park mode
|
||||
|
||||
In certain circumstances, the XHCI SuperSpeed instance in park mode
|
||||
can fail to recover, thus on Amlogic G12A/G12B/SM1 SoCs when there is high
|
||||
load on the single XHCI SuperSpeed instance, the controller can crash like:
|
||||
xhci-hcd xhci-hcd.0.auto: xHCI host not responding to stop endpoint command.
|
||||
xhci-hcd xhci-hcd.0.auto: Host halt failed, -110
|
||||
xhci-hcd xhci-hcd.0.auto: xHCI host controller not responding, assume dead
|
||||
xhci-hcd xhci-hcd.0.auto: xHCI host not responding to stop endpoint command.
|
||||
hub 2-1.1:1.0: hub_ext_port_status failed (err = -22)
|
||||
xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
|
||||
usb 2-1.1-port1: cannot reset (err = -22)
|
||||
|
||||
Setting the PARKMODE_DISABLE_SS bit in the DWC3_USB3_GUCTL1 mitigates
|
||||
the issue. The bit is described as :
|
||||
"When this bit is set to '1' all SS bus instances in park mode are disabled"
|
||||
|
||||
CC: Dongjin Kim <tobetter@gmail.com>
|
||||
Cc: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Reported-by: Tim <elatllat@gmail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/usb/dwc3/core.c | 5 +++++
|
||||
drivers/usb/dwc3/core.h | 4 ++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
|
||||
index 1d85c42b9c67..43bd5b1ea9e2 100644
|
||||
--- a/drivers/usb/dwc3/core.c
|
||||
+++ b/drivers/usb/dwc3/core.c
|
||||
@@ -1029,6 +1029,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
if (dwc->dis_tx_ipgap_linecheck_quirk)
|
||||
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
|
||||
|
||||
+ if (dwc->parkmode_disable_ss_quirk)
|
||||
+ reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
|
||||
+
|
||||
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
|
||||
}
|
||||
|
||||
@@ -1342,6 +1345,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
||||
"snps,dis-del-phy-power-chg-quirk");
|
||||
dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
|
||||
"snps,dis-tx-ipgap-linecheck-quirk");
|
||||
+ dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
|
||||
+ "snps,parkmode-disable-ss-quirk");
|
||||
|
||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||
"snps,tx_de_emphasis_quirk");
|
||||
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
|
||||
index 77c4a9abe365..3ecc69c5b150 100644
|
||||
--- a/drivers/usb/dwc3/core.h
|
||||
+++ b/drivers/usb/dwc3/core.h
|
||||
@@ -249,6 +249,7 @@
|
||||
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
|
||||
|
||||
/* Global User Control 1 Register */
|
||||
+#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
|
||||
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
|
||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||
|
||||
@@ -1024,6 +1025,8 @@ struct dwc3_scratchpad_array {
|
||||
* change quirk.
|
||||
* @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
|
||||
* check during HS transmit.
|
||||
+ * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
|
||||
+ * instances in park mode.
|
||||
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
|
||||
* @tx_de_emphasis: Tx de-emphasis value
|
||||
* 0 - -6dB de-emphasis
|
||||
@@ -1215,6 +1218,7 @@ struct dwc3 {
|
||||
unsigned dis_u2_freeclk_exists_quirk:1;
|
||||
unsigned dis_del_phy_power_chg_quirk:1;
|
||||
unsigned dis_tx_ipgap_linecheck_quirk:1;
|
||||
+ unsigned parkmode_disable_ss_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,40 +0,0 @@
|
||||
From 3bbafb8837231ef9af9836e0cc8deccfe0f65290 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 17 Oct 2019 21:05:34 +0000
|
||||
Subject: [PATCH 078/146] FROMLIST: arm64: dts: g12-common: add
|
||||
parkmode_disable_ss_quirk on DWC3 controller
|
||||
|
||||
When high load on the DWC3 SuperSpee port, the controller crashed as:
|
||||
[ 221.141621] xhci-hcd xhci-hcd.0.auto: xHCI host not responding to stop endpoint command.
|
||||
[ 221.157631] xhci-hcd xhci-hcd.0.auto: Host halt failed, -110
|
||||
[ 221.157635] xhci-hcd xhci-hcd.0.auto: xHCI host controller not responding, assume dead
|
||||
[ 221.159901] xhci-hcd xhci-hcd.0.auto: xHCI host not responding to stop endpoint command.
|
||||
[ 221.159961] hub 2-1.1:1.0: hub_ext_port_status failed (err = -22)
|
||||
[ 221.160076] xhci-hcd xhci-hcd.0.auto: HC died; cleaning up
|
||||
[ 221.165946] usb 2-1.1-port1: cannot reset (err = -22)
|
||||
|
||||
Setting the parkmode_disable_ss_quirk quirk fixes the issue.
|
||||
|
||||
CC: Dongjin Kim <tobetter@gmail.com>
|
||||
Cc: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
Reported-by: Tim <elatllat@gmail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
index 3deace05d345..d66b9ad9c966 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi
|
||||
@@ -2231,6 +2231,7 @@
|
||||
dr_mode = "host";
|
||||
snps,dis_u2_susphy_quirk;
|
||||
snps,quirk-frame-length-adjustment;
|
||||
+ snps,parkmode-disable-ss-quirk;
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,622 +0,0 @@
|
||||
From f7d74763a9958c1239d4aef478ea770ead734ef3 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Mon, 6 Jan 2020 15:34:06 +0100
|
||||
Subject: [PATCH 079/146] FROMLIST: drm/bridge: Add a drm_bridge_state object
|
||||
|
||||
One of the last remaining objects to not have its atomic state.
|
||||
|
||||
This is being motivated by our attempt to support runtime bus-format
|
||||
negotiation between elements of the bridge chain.
|
||||
This patch just paves the road for such a feature by adding a new
|
||||
drm_bridge_state object inheriting from drm_private_obj so we can
|
||||
re-use some of the existing state initialization/tracking logic.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v9:
|
||||
* Clarify the fact that the bridge->atomic_reset() and
|
||||
{connector,plane,crtc,...}->reset() semantics are different
|
||||
* Move the drm_atomic_private_obj_init() call back to
|
||||
drm_bridge_attach()
|
||||
* Check the presence of ->atomic_duplicate_state instead of
|
||||
->atomic_reset in drm_atomic_add_encoder_bridges()
|
||||
* Fix copy&paste errors in the atomic bridge state helpers doc
|
||||
* Add A-b/R-b tags
|
||||
|
||||
v8:
|
||||
* Move bridge state helpers out of the CONFIG_DEBUGFS section
|
||||
|
||||
v7:
|
||||
* Move helpers, struct-defs, ... to atomic helper files to avoid the
|
||||
drm -> drm_kms_helper -> drm circular dep
|
||||
* Stop providing default implementation for atomic state reset,
|
||||
duplicate and destroy hooks (has to do with the helper/core split)
|
||||
* Drop all R-b/T-b as helpers have now be moved to other places
|
||||
|
||||
v6:
|
||||
* Made helpers private, removed doc and moved them to satisfy dependencies
|
||||
* Renamed helpers to _default_
|
||||
|
||||
v5:
|
||||
* Re-introduced the helpers from v4
|
||||
|
||||
v4:
|
||||
* Fix the doc
|
||||
* Kill default helpers (inlined)
|
||||
* Fix drm_atomic_get_bridge_state() to check for an ERR_PTR()
|
||||
* Add Neil's R-b
|
||||
|
||||
v3:
|
||||
* No changes
|
||||
|
||||
v2:
|
||||
* Use drm_for_each_bridge_in_chain()
|
||||
* Rename helpers to be more consistent with the rest of the DRM API
|
||||
* Improve/fix the doc
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
---
|
||||
drivers/gpu/drm/drm_atomic.c | 116 ++++++++++++++++++++++
|
||||
drivers/gpu/drm/drm_atomic_helper.c | 20 ++++
|
||||
drivers/gpu/drm/drm_atomic_state_helper.c | 103 +++++++++++++++++++
|
||||
drivers/gpu/drm/drm_bridge.c | 59 ++++++++++-
|
||||
include/drm/drm_atomic.h | 34 +++++++
|
||||
include/drm/drm_atomic_state_helper.h | 13 +++
|
||||
include/drm/drm_bridge.h | 60 +++++++++++
|
||||
7 files changed, 400 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
|
||||
index d33691512a8e..65c46ed049c5 100644
|
||||
--- a/drivers/gpu/drm/drm_atomic.c
|
||||
+++ b/drivers/gpu/drm/drm_atomic.c
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_uapi.h>
|
||||
+#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_drv.h>
|
||||
@@ -1017,6 +1018,121 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
|
||||
connector->funcs->atomic_print_state(p, state);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * drm_atomic_get_bridge_state - get bridge state
|
||||
+ * @state: global atomic state object
|
||||
+ * @bridge: bridge to get state object for
|
||||
+ *
|
||||
+ * This function returns the bridge state for the given bridge, allocating it
|
||||
+ * if needed. It will also grab the relevant bridge lock to make sure that the
|
||||
+ * state is consistent.
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ *
|
||||
+ * Either the allocated state or the error code encoded into the pointer. When
|
||||
+ * the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
+ * entire atomic sequence must be restarted.
|
||||
+ */
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct drm_private_state *obj_state;
|
||||
+
|
||||
+ obj_state = drm_atomic_get_private_obj_state(state, &bridge->base);
|
||||
+ if (IS_ERR(obj_state))
|
||||
+ return ERR_CAST(obj_state);
|
||||
+
|
||||
+ return drm_priv_to_bridge_state(obj_state);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_get_bridge_state);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_get_old_bridge_state - get old bridge state, if it exists
|
||||
+ * @state: global atomic state object
|
||||
+ * @bridge: bridge to grab
|
||||
+ *
|
||||
+ * This function returns the old bridge state for the given bridge, or NULL if
|
||||
+ * the bridge is not part of the global atomic state.
|
||||
+ */
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct drm_private_state *obj_state;
|
||||
+
|
||||
+ obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base);
|
||||
+ if (!obj_state)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return drm_priv_to_bridge_state(obj_state);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_get_old_bridge_state);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_get_new_bridge_state - get new bridge state, if it exists
|
||||
+ * @state: global atomic state object
|
||||
+ * @bridge: bridge to grab
|
||||
+ *
|
||||
+ * This function returns the new bridge state for the given bridge, or NULL if
|
||||
+ * the bridge is not part of the global atomic state.
|
||||
+ */
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct drm_private_state *obj_state;
|
||||
+
|
||||
+ obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base);
|
||||
+ if (!obj_state)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return drm_priv_to_bridge_state(obj_state);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_get_new_bridge_state);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_add_encoder_bridges - add bridges attached to an encoder
|
||||
+ * @state: atomic state
|
||||
+ * @encoder: DRM encoder
|
||||
+ *
|
||||
+ * This function adds all bridges attached to @encoder. This is needed to add
|
||||
+ * bridge states to @state and make them available when
|
||||
+ * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are
|
||||
+ * called
|
||||
+ *
|
||||
+ * Returns:
|
||||
+ * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK
|
||||
+ * then the w/w mutex code has detected a deadlock and the entire atomic
|
||||
+ * sequence must be restarted. All other errors are fatal.
|
||||
+ */
|
||||
+int
|
||||
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
|
||||
+ struct drm_encoder *encoder)
|
||||
+{
|
||||
+ struct drm_bridge_state *bridge_state;
|
||||
+ struct drm_bridge *bridge;
|
||||
+
|
||||
+ if (!encoder)
|
||||
+ return 0;
|
||||
+
|
||||
+ DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n",
|
||||
+ encoder->base.id, encoder->name, state);
|
||||
+
|
||||
+ drm_for_each_bridge_in_chain(encoder, bridge) {
|
||||
+ /* Skip bridges that don't implement the atomic state hooks. */
|
||||
+ if (!bridge->funcs->atomic_duplicate_state)
|
||||
+ continue;
|
||||
+
|
||||
+ bridge_state = drm_atomic_get_bridge_state(state, bridge);
|
||||
+ if (IS_ERR(bridge_state))
|
||||
+ return PTR_ERR(bridge_state);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_add_encoder_bridges);
|
||||
+
|
||||
/**
|
||||
* drm_atomic_add_affected_connectors - add connectors for CRTC
|
||||
* @state: atomic state
|
||||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
index 4511c2e07bb9..ad8eae98d9e8 100644
|
||||
--- a/drivers/gpu/drm/drm_atomic_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
@@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Iterate over all connectors again, and add all affected bridges to
|
||||
+ * the state.
|
||||
+ */
|
||||
+ for_each_oldnew_connector_in_state(state, connector,
|
||||
+ old_connector_state,
|
||||
+ new_connector_state, i) {
|
||||
+ struct drm_encoder *encoder;
|
||||
+
|
||||
+ encoder = old_connector_state->best_encoder;
|
||||
+ ret = drm_atomic_add_encoder_bridges(state, encoder);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ encoder = new_connector_state->best_encoder;
|
||||
+ ret = drm_atomic_add_encoder_bridges(state, encoder);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
ret = mode_valid(state);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
|
||||
index 7cf3cf936547..33141d2cdad4 100644
|
||||
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
+#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_device.h>
|
||||
@@ -551,3 +552,105 @@ void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj
|
||||
memcpy(state, obj->state, sizeof(*state));
|
||||
}
|
||||
EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
|
||||
+
|
||||
+/**
|
||||
+ * __drm_atomic_helper_bridge_duplicate_state() - Copy atomic bridge state
|
||||
+ * @bridge: bridge object
|
||||
+ * @state: atomic bridge state
|
||||
+ *
|
||||
+ * Copies atomic state from a bridge's current state and resets inferred values.
|
||||
+ * This is useful for drivers that subclass the bridge state.
|
||||
+ */
|
||||
+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state)
|
||||
+{
|
||||
+ __drm_atomic_helper_private_obj_duplicate_state(&bridge->base,
|
||||
+ &state->base);
|
||||
+ state->bridge = bridge;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_helper_bridge_duplicate_state() - Duplicate a bridge state object
|
||||
+ * @bridge: bridge object
|
||||
+ *
|
||||
+ * Allocates a new bridge state and initializes it with the current bridge
|
||||
+ * state values. This helper is meant to be used as a bridge
|
||||
+ * &drm_bridge_funcs.atomic_duplicate_state hook for bridges that don't
|
||||
+ * subclass the bridge state.
|
||||
+ */
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct drm_bridge_state *new;
|
||||
+
|
||||
+ if (WARN_ON(!bridge->base.state))
|
||||
+ return NULL;
|
||||
+
|
||||
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||
+ if (new)
|
||||
+ __drm_atomic_helper_bridge_duplicate_state(bridge, new);
|
||||
+
|
||||
+ return new;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_helper_bridge_duplicate_state);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_helper_bridge_destroy_state() - Destroy a bridge state object
|
||||
+ * @bridge: the bridge this state refers to
|
||||
+ * @state: bridge state to destroy
|
||||
+ *
|
||||
+ * Destroys a bridge state previously created by
|
||||
+ * &drm_atomic_helper_bridge_reset() or
|
||||
+ * &drm_atomic_helper_bridge_duplicate_state(). This helper is meant to be
|
||||
+ * used as a bridge &drm_bridge_funcs.atomic_destroy_state hook for bridges
|
||||
+ * that don't subclass the bridge state.
|
||||
+ */
|
||||
+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state)
|
||||
+{
|
||||
+ kfree(state);
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state);
|
||||
+
|
||||
+/**
|
||||
+ * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its
|
||||
+ * default
|
||||
+ * @bridge: the bridge this state refers to
|
||||
+ * @state: bridge state to initialize
|
||||
+ *
|
||||
+ * Initializes the bridge state to default values. This is meant to be called
|
||||
+ * by the bridge &drm_bridge_funcs.atomic_reset hook for bridges that subclass
|
||||
+ * the bridge state.
|
||||
+ */
|
||||
+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state)
|
||||
+{
|
||||
+ memset(state, 0, sizeof(*state));
|
||||
+ state->bridge = bridge;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_helper_bridge_reset() - Allocate and initialize a bridge state
|
||||
+ * to its default
|
||||
+ * @bridge: the bridge this state refers to
|
||||
+ * @state: bridge state to initialize
|
||||
+ *
|
||||
+ * Allocates the bridge state and initializes it to default values. This helper
|
||||
+ * is meant to be used as a bridge &drm_bridge_funcs.atomic_reset hook for
|
||||
+ * bridges that don't subclass the bridge state.
|
||||
+ */
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge)
|
||||
+{
|
||||
+ struct drm_bridge_state *bridge_state;
|
||||
+
|
||||
+ bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL);
|
||||
+ if (!bridge_state)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ __drm_atomic_helper_bridge_reset(bridge, bridge_state);
|
||||
+ return bridge_state;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_helper_bridge_reset);
|
||||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
|
||||
index c2cf0c90fa26..6b08158ebb7e 100644
|
||||
--- a/drivers/gpu/drm/drm_bridge.c
|
||||
+++ b/drivers/gpu/drm/drm_bridge.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
+#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
|
||||
@@ -89,6 +90,31 @@ void drm_bridge_remove(struct drm_bridge *bridge)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_remove);
|
||||
|
||||
+static struct drm_private_state *
|
||||
+drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj)
|
||||
+{
|
||||
+ struct drm_bridge *bridge = drm_priv_to_bridge(obj);
|
||||
+ struct drm_bridge_state *state;
|
||||
+
|
||||
+ state = bridge->funcs->atomic_duplicate_state(bridge);
|
||||
+ return state ? &state->base : NULL;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
|
||||
+ struct drm_private_state *s)
|
||||
+{
|
||||
+ struct drm_bridge_state *state = drm_priv_to_bridge_state(s);
|
||||
+ struct drm_bridge *bridge = drm_priv_to_bridge(obj);
|
||||
+
|
||||
+ bridge->funcs->atomic_destroy_state(bridge, state);
|
||||
+}
|
||||
+
|
||||
+static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
|
||||
+ .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
|
||||
+ .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* drm_bridge_attach - attach the bridge to an encoder's chain
|
||||
*
|
||||
@@ -135,15 +161,35 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
||||
|
||||
if (bridge->funcs->attach) {
|
||||
ret = bridge->funcs->attach(bridge);
|
||||
- if (ret < 0) {
|
||||
- list_del(&bridge->chain_node);
|
||||
- bridge->dev = NULL;
|
||||
- bridge->encoder = NULL;
|
||||
- return ret;
|
||||
+ if (ret < 0)
|
||||
+ goto err_reset_bridge;
|
||||
+ }
|
||||
+
|
||||
+ if (bridge->funcs->atomic_reset) {
|
||||
+ struct drm_bridge_state *state;
|
||||
+
|
||||
+ state = bridge->funcs->atomic_reset(bridge);
|
||||
+ if (IS_ERR(state)) {
|
||||
+ ret = PTR_ERR(state);
|
||||
+ goto err_detach_bridge;
|
||||
}
|
||||
+
|
||||
+ drm_atomic_private_obj_init(bridge->dev, &bridge->base,
|
||||
+ &state->base,
|
||||
+ &drm_bridge_priv_state_funcs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
+
|
||||
+err_detach_bridge:
|
||||
+ if (bridge->funcs->detach)
|
||||
+ bridge->funcs->detach(bridge);
|
||||
+
|
||||
+err_reset_bridge:
|
||||
+ bridge->dev = NULL;
|
||||
+ bridge->encoder = NULL;
|
||||
+ list_del(&bridge->chain_node);
|
||||
+ return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_attach);
|
||||
|
||||
@@ -155,6 +201,9 @@ void drm_bridge_detach(struct drm_bridge *bridge)
|
||||
if (WARN_ON(!bridge->dev))
|
||||
return;
|
||||
|
||||
+ if (bridge->funcs->atomic_reset)
|
||||
+ drm_atomic_private_obj_fini(&bridge->base);
|
||||
+
|
||||
if (bridge->funcs->detach)
|
||||
bridge->funcs->detach(bridge);
|
||||
|
||||
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
|
||||
index 951dfb15c27b..82a888769b3d 100644
|
||||
--- a/include/drm/drm_atomic.h
|
||||
+++ b/include/drm/drm_atomic.h
|
||||
@@ -669,6 +669,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state,
|
||||
return plane->state;
|
||||
}
|
||||
|
||||
+int __must_check
|
||||
+drm_atomic_add_encoder_bridges(struct drm_atomic_state *state,
|
||||
+ struct drm_encoder *encoder);
|
||||
int __must_check
|
||||
drm_atomic_add_affected_connectors(struct drm_atomic_state *state,
|
||||
struct drm_crtc *crtc);
|
||||
@@ -992,4 +995,35 @@ drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
|
||||
return state->active || state->self_refresh_active;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * struct drm_bridge_state - Atomic bridge state object
|
||||
+ */
|
||||
+struct drm_bridge_state {
|
||||
+ /**
|
||||
+ * @base: inherit from &drm_private_state
|
||||
+ */
|
||||
+ struct drm_private_state base;
|
||||
+
|
||||
+ /**
|
||||
+ * @bridge: the bridge this state refers to
|
||||
+ */
|
||||
+ struct drm_bridge *bridge;
|
||||
+};
|
||||
+
|
||||
+static inline struct drm_bridge_state *
|
||||
+drm_priv_to_bridge_state(struct drm_private_state *priv)
|
||||
+{
|
||||
+ return container_of(priv, struct drm_bridge_state, base);
|
||||
+}
|
||||
+
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge);
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_old_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge);
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_get_new_bridge_state(struct drm_atomic_state *state,
|
||||
+ struct drm_bridge *bridge);
|
||||
+
|
||||
#endif /* DRM_ATOMIC_H_ */
|
||||
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
|
||||
index 8171dea4cc22..3f8f1d627f7c 100644
|
||||
--- a/include/drm/drm_atomic_state_helper.h
|
||||
+++ b/include/drm/drm_atomic_state_helper.h
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
+struct drm_bridge;
|
||||
+struct drm_bridge_state;
|
||||
struct drm_crtc;
|
||||
struct drm_crtc_state;
|
||||
struct drm_plane;
|
||||
@@ -80,3 +82,14 @@ void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
|
||||
struct drm_connector_state *state);
|
||||
void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
|
||||
struct drm_private_state *state);
|
||||
+
|
||||
+void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state);
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge);
|
||||
+void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state);
|
||||
+void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state);
|
||||
+struct drm_bridge_state *
|
||||
+drm_atomic_helper_bridge_reset(struct drm_bridge *bridge);
|
||||
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
|
||||
index 694e153a7531..8883dcfe63cb 100644
|
||||
--- a/include/drm/drm_bridge.h
|
||||
+++ b/include/drm/drm_bridge.h
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/ctype.h>
|
||||
+
|
||||
+#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_mode_object.h>
|
||||
#include <drm/drm_modes.h>
|
||||
@@ -338,6 +340,56 @@ struct drm_bridge_funcs {
|
||||
*/
|
||||
void (*atomic_post_disable)(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *old_state);
|
||||
+
|
||||
+ /**
|
||||
+ * @atomic_duplicate_state:
|
||||
+ *
|
||||
+ * Duplicate the current bridge state object (which is guaranteed to be
|
||||
+ * non-NULL).
|
||||
+ *
|
||||
+ * The atomic_duplicate_state() is optional. When not implemented the
|
||||
+ * core allocates a drm_bridge_state object and calls
|
||||
+ * &__drm_atomic_helper_bridge_duplicate_state() to initialize it.
|
||||
+ *
|
||||
+ * RETURNS:
|
||||
+ * A valid drm_bridge_state object or NULL if the allocation fails.
|
||||
+ */
|
||||
+ struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge);
|
||||
+
|
||||
+ /**
|
||||
+ * @atomic_destroy_state:
|
||||
+ *
|
||||
+ * Destroy a bridge state object previously allocated by
|
||||
+ * &drm_bridge_funcs.atomic_duplicate_state().
|
||||
+ *
|
||||
+ * The atomic_destroy_state hook is optional. When not implemented the
|
||||
+ * core calls kfree() on the state.
|
||||
+ */
|
||||
+ void (*atomic_destroy_state)(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *state);
|
||||
+
|
||||
+ /**
|
||||
+ * @atomic_reset:
|
||||
+ *
|
||||
+ * Reset the bridge to a predefined state (or retrieve its current
|
||||
+ * state) and return a &drm_bridge_state object matching this state.
|
||||
+ * This function is called at attach time.
|
||||
+ *
|
||||
+ * The atomic_reset hook is mandatory if the bridge implements any of
|
||||
+ * the atomic hooks, and should be left unassigned otherwise.
|
||||
+ *
|
||||
+ * Note that the atomic_reset() semantics is not exactly matching the
|
||||
+ * reset() semantics found on other components (connector, plane, ...).
|
||||
+ * 1/ The reset operation happens when the bridge is attached, not when
|
||||
+ * drm_mode_config_reset() is called
|
||||
+ * 2/ It's meant to be used exclusively on bridges that have been
|
||||
+ * converted to the ATOMIC API
|
||||
+ *
|
||||
+ * RETURNS:
|
||||
+ * A valid drm_bridge_state object in case of success, an ERR_PTR()
|
||||
+ * giving the reason of the failure otherwise.
|
||||
+ */
|
||||
+ struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -380,6 +432,8 @@ struct drm_bridge_timings {
|
||||
* struct drm_bridge - central DRM bridge control structure
|
||||
*/
|
||||
struct drm_bridge {
|
||||
+ /** @base: inherit from &drm_private_object */
|
||||
+ struct drm_private_obj base;
|
||||
/** @dev: DRM device this bridge belongs to */
|
||||
struct drm_device *dev;
|
||||
/** @encoder: encoder to which this bridge is connected */
|
||||
@@ -404,6 +458,12 @@ struct drm_bridge {
|
||||
void *driver_private;
|
||||
};
|
||||
|
||||
+static inline struct drm_bridge *
|
||||
+drm_priv_to_bridge(struct drm_private_obj *priv)
|
||||
+{
|
||||
+ return container_of(priv, struct drm_bridge, base);
|
||||
+}
|
||||
+
|
||||
void drm_bridge_add(struct drm_bridge *bridge);
|
||||
void drm_bridge_remove(struct drm_bridge *bridge);
|
||||
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From 2a785aa31675dbdc1039891e3b69ef3d4a680dbd Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Tue, 21 Jan 2020 16:34:32 +0100
|
||||
Subject: [PATCH 080/146] FROMLIST: drm/rcar-du: Plug atomic state hooks to the
|
||||
default implementation
|
||||
|
||||
This is needed to pass a bridge state to all atomic hooks, if we don't
|
||||
do that, the core can't duplicate/create bridge states.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v9:
|
||||
* Add Neil's R-b
|
||||
* Move earlier in the series
|
||||
|
||||
v8:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* New patch
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/rcar-du/rcar_lvds.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
index 8ffa4fbbdeb3..3a254f1b29fe 100644
|
||||
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
@@ -682,6 +682,9 @@ static void rcar_lvds_detach(struct drm_bridge *bridge)
|
||||
static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
|
||||
.attach = rcar_lvds_attach,
|
||||
.detach = rcar_lvds_detach,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.atomic_enable = rcar_lvds_atomic_enable,
|
||||
.atomic_disable = rcar_lvds_atomic_disable,
|
||||
.mode_fixup = rcar_lvds_mode_fixup,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From d1cf8cf8857aa4f9ff8750717d3c2371052a94ed Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Tue, 21 Jan 2020 16:35:10 +0100
|
||||
Subject: [PATCH 081/146] FROMLIST: drm/bridge: analogix: Plug atomic state
|
||||
hooks to the default implementation
|
||||
|
||||
This is needed to pass a bridge state to all atomic hooks, if we don't
|
||||
do that, the core can't duplicate/create bridge states.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v9:
|
||||
* Add Neil's R-b
|
||||
* Move earlier in the series
|
||||
|
||||
v8:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* New patch
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
index 6effe532f820..aaaec39ec2a7 100644
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1563,6 +1563,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable,
|
||||
.atomic_enable = analogix_dp_bridge_atomic_enable,
|
||||
.atomic_disable = analogix_dp_bridge_atomic_disable,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,333 +0,0 @@
|
||||
From a89ba179e291fd52ec7597baa2953d50e513cefd Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Mon, 6 Jan 2020 15:34:07 +0100
|
||||
Subject: [PATCH 082/146] FROMLIST: drm/bridge: Patch atomic hooks to take a
|
||||
drm_bridge_state
|
||||
|
||||
This way the drm_bridge_funcs interface is consistent with the rest of
|
||||
the subsystem.
|
||||
|
||||
The drivers implementing those hooks are patched too.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Adjust things to the bridge_state changes
|
||||
|
||||
v6:
|
||||
* Also fixed rcar-du/rcar_lvds.c same as analogix/analogix_dp_core.c
|
||||
|
||||
v5:
|
||||
* No changes
|
||||
|
||||
v4:
|
||||
* Rename func params into old_bridge_state
|
||||
* Add Laurent's Rb
|
||||
|
||||
v3:
|
||||
* Old state clarification moved to a separate patch
|
||||
|
||||
v2:
|
||||
* Pass the old bridge state
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
[narmstrong: renamed state as old_bridge_state in rcar_lvds_atomic_disable]
|
||||
Reviewed by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Tested-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
---
|
||||
.../drm/bridge/analogix/analogix_dp_core.c | 41 +++++++------
|
||||
drivers/gpu/drm/drm_bridge.c | 61 +++++++++++++++----
|
||||
drivers/gpu/drm/rcar-du/rcar_lvds.c | 8 ++-
|
||||
include/drm/drm_bridge.h | 8 +--
|
||||
4 files changed, 82 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
index aaaec39ec2a7..dfb59a5fefea 100644
|
||||
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
|
||||
@@ -1289,19 +1289,21 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp,
|
||||
return conn_state->crtc;
|
||||
}
|
||||
|
||||
-static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+static void
|
||||
+analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
+ struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int ret;
|
||||
|
||||
- crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
+ crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
- old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
|
||||
+ old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
|
||||
/* Don't touch the panel if we're coming back from PSR */
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active)
|
||||
return;
|
||||
@@ -1366,20 +1368,22 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+static void
|
||||
+analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
+ struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *old_crtc_state;
|
||||
int timeout_loop = 0;
|
||||
int ret;
|
||||
|
||||
- crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
+ crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
- old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
|
||||
+ old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc);
|
||||
/* Not a full enable, just disable PSR and continue */
|
||||
if (old_crtc_state && old_crtc_state->self_refresh_active) {
|
||||
ret = analogix_dp_disable_psr(dp);
|
||||
@@ -1440,18 +1444,20 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
|
||||
dp->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
}
|
||||
|
||||
-static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+static void
|
||||
+analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
+ struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state = NULL;
|
||||
|
||||
- crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
+ crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
goto out;
|
||||
|
||||
- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
+ new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
|
||||
if (!new_crtc_state)
|
||||
goto out;
|
||||
|
||||
@@ -1463,20 +1469,21 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
|
||||
analogix_dp_bridge_disable(bridge);
|
||||
}
|
||||
|
||||
-static
|
||||
-void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+static void
|
||||
+analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
+ struct drm_atomic_state *old_state = old_bridge_state->base.state;
|
||||
struct analogix_dp_device *dp = bridge->driver_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
int ret;
|
||||
|
||||
- crtc = analogix_dp_get_new_crtc(dp, state);
|
||||
+ crtc = analogix_dp_get_new_crtc(dp, old_state);
|
||||
if (!crtc)
|
||||
return;
|
||||
|
||||
- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||
+ new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc);
|
||||
if (!new_crtc_state || !new_crtc_state->self_refresh_active)
|
||||
return;
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
|
||||
index 6b08158ebb7e..f6206e655da4 100644
|
||||
--- a/drivers/gpu/drm/drm_bridge.c
|
||||
+++ b/drivers/gpu/drm/drm_bridge.c
|
||||
@@ -458,10 +458,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
- if (iter->funcs->atomic_disable)
|
||||
- iter->funcs->atomic_disable(iter, old_state);
|
||||
- else if (iter->funcs->disable)
|
||||
+ if (iter->funcs->atomic_disable) {
|
||||
+ struct drm_bridge_state *old_bridge_state;
|
||||
+
|
||||
+ old_bridge_state =
|
||||
+ drm_atomic_get_old_bridge_state(old_state,
|
||||
+ iter);
|
||||
+ if (WARN_ON(!old_bridge_state))
|
||||
+ return;
|
||||
+
|
||||
+ iter->funcs->atomic_disable(iter, old_bridge_state);
|
||||
+ } else if (iter->funcs->disable) {
|
||||
iter->funcs->disable(iter);
|
||||
+ }
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
@@ -492,10 +501,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
||||
- if (bridge->funcs->atomic_post_disable)
|
||||
- bridge->funcs->atomic_post_disable(bridge, old_state);
|
||||
- else if (bridge->funcs->post_disable)
|
||||
+ if (bridge->funcs->atomic_post_disable) {
|
||||
+ struct drm_bridge_state *old_bridge_state;
|
||||
+
|
||||
+ old_bridge_state =
|
||||
+ drm_atomic_get_old_bridge_state(old_state,
|
||||
+ bridge);
|
||||
+ if (WARN_ON(!old_bridge_state))
|
||||
+ return;
|
||||
+
|
||||
+ bridge->funcs->atomic_post_disable(bridge,
|
||||
+ old_bridge_state);
|
||||
+ } else if (bridge->funcs->post_disable) {
|
||||
bridge->funcs->post_disable(bridge);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable);
|
||||
@@ -524,10 +543,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
- if (iter->funcs->atomic_pre_enable)
|
||||
- iter->funcs->atomic_pre_enable(iter, old_state);
|
||||
- else if (iter->funcs->pre_enable)
|
||||
+ if (iter->funcs->atomic_pre_enable) {
|
||||
+ struct drm_bridge_state *old_bridge_state;
|
||||
+
|
||||
+ old_bridge_state =
|
||||
+ drm_atomic_get_old_bridge_state(old_state,
|
||||
+ iter);
|
||||
+ if (WARN_ON(!old_bridge_state))
|
||||
+ return;
|
||||
+
|
||||
+ iter->funcs->atomic_pre_enable(iter, old_bridge_state);
|
||||
+ } else if (iter->funcs->pre_enable) {
|
||||
iter->funcs->pre_enable(iter);
|
||||
+ }
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
@@ -557,10 +585,19 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
|
||||
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) {
|
||||
- if (bridge->funcs->atomic_enable)
|
||||
- bridge->funcs->atomic_enable(bridge, old_state);
|
||||
- else if (bridge->funcs->enable)
|
||||
+ if (bridge->funcs->atomic_enable) {
|
||||
+ struct drm_bridge_state *old_bridge_state;
|
||||
+
|
||||
+ old_bridge_state =
|
||||
+ drm_atomic_get_old_bridge_state(old_state,
|
||||
+ bridge);
|
||||
+ if (WARN_ON(!old_bridge_state))
|
||||
+ return;
|
||||
+
|
||||
+ bridge->funcs->atomic_enable(bridge, old_bridge_state);
|
||||
+ } else if (bridge->funcs->enable) {
|
||||
bridge->funcs->enable(bridge);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
|
||||
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
index 3a254f1b29fe..06432c881e07 100644
|
||||
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
|
||||
@@ -590,8 +590,9 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
}
|
||||
|
||||
static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
+ struct drm_atomic_state *state = old_bridge_state->base.state;
|
||||
struct drm_connector *connector;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
@@ -603,7 +604,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
|
||||
}
|
||||
|
||||
static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *state)
|
||||
+ struct drm_bridge_state *old_bridge_state)
|
||||
{
|
||||
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
|
||||
|
||||
@@ -618,7 +619,8 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
|
||||
|
||||
/* Disable the companion LVDS encoder in dual-link mode. */
|
||||
if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion)
|
||||
- lvds->companion->funcs->atomic_disable(lvds->companion, state);
|
||||
+ lvds->companion->funcs->atomic_disable(lvds->companion,
|
||||
+ old_bridge_state);
|
||||
|
||||
clk_disable_unprepare(lvds->clocks.mod);
|
||||
}
|
||||
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
|
||||
index 8883dcfe63cb..df22f909141f 100644
|
||||
--- a/include/drm/drm_bridge.h
|
||||
+++ b/include/drm/drm_bridge.h
|
||||
@@ -265,7 +265,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_pre_enable callback is optional.
|
||||
*/
|
||||
void (*atomic_pre_enable)(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *old_state);
|
||||
+ struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_enable:
|
||||
@@ -290,7 +290,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_enable callback is optional.
|
||||
*/
|
||||
void (*atomic_enable)(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *old_state);
|
||||
+ struct drm_bridge_state *old_bridge_state);
|
||||
/**
|
||||
* @atomic_disable:
|
||||
*
|
||||
@@ -313,7 +313,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_disable callback is optional.
|
||||
*/
|
||||
void (*atomic_disable)(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *old_state);
|
||||
+ struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_post_disable:
|
||||
@@ -339,7 +339,7 @@ struct drm_bridge_funcs {
|
||||
* The @atomic_post_disable callback is optional.
|
||||
*/
|
||||
void (*atomic_post_disable)(struct drm_bridge *bridge,
|
||||
- struct drm_atomic_state *old_state);
|
||||
+ struct drm_bridge_state *old_bridge_state);
|
||||
|
||||
/**
|
||||
* @atomic_duplicate_state:
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,202 +0,0 @@
|
||||
From 307c2206d029f8b006009e53a7143cabfe6002af Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Mon, 6 Jan 2020 15:34:08 +0100
|
||||
Subject: [PATCH 083/146] FROMLIST: drm/bridge: Add an ->atomic_check() hook
|
||||
|
||||
So that bridge drivers have a way to check/reject an atomic operation.
|
||||
The drm_atomic_bridge_chain_check() (which is just a wrapper around
|
||||
the ->atomic_check() hook) is called in place of
|
||||
drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented,
|
||||
the core falls back on ->mode_fixup(), so the behavior should stay
|
||||
the same for existing bridge drivers).
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Fix a NULL pointer dereference
|
||||
|
||||
v5 -> v6:
|
||||
* No changes
|
||||
|
||||
v4:
|
||||
* Add R-bs
|
||||
|
||||
v3:
|
||||
* No changes
|
||||
|
||||
v2:
|
||||
* Clarify the fact that ->atomic_check() is replacing ->mode_fixup()
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Reviewed by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Tested-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/drm_atomic_helper.c | 12 +++---
|
||||
drivers/gpu/drm/drm_bridge.c | 66 +++++++++++++++++++++++++++++
|
||||
include/drm/drm_bridge.h | 29 ++++++++++++-
|
||||
3 files changed, 100 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
index ad8eae98d9e8..afe14f72a824 100644
|
||||
--- a/drivers/gpu/drm/drm_atomic_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
@@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state)
|
||||
funcs = encoder->helper_private;
|
||||
|
||||
bridge = drm_bridge_chain_get_first_bridge(encoder);
|
||||
- ret = drm_bridge_chain_mode_fixup(bridge,
|
||||
- &new_crtc_state->mode,
|
||||
- &new_crtc_state->adjusted_mode);
|
||||
- if (!ret) {
|
||||
- DRM_DEBUG_ATOMIC("Bridge fixup failed\n");
|
||||
- return -EINVAL;
|
||||
+ ret = drm_atomic_bridge_chain_check(bridge,
|
||||
+ new_crtc_state,
|
||||
+ new_conn_state);
|
||||
+ if (ret) {
|
||||
+ DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
if (funcs && funcs->atomic_check) {
|
||||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
|
||||
index f6206e655da4..c8beb1385771 100644
|
||||
--- a/drivers/gpu/drm/drm_bridge.c
|
||||
+++ b/drivers/gpu/drm/drm_bridge.c
|
||||
@@ -602,6 +602,72 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
|
||||
|
||||
+static int drm_atomic_bridge_check(struct drm_bridge *bridge,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ if (bridge->funcs->atomic_check) {
|
||||
+ struct drm_bridge_state *bridge_state;
|
||||
+ int ret;
|
||||
+
|
||||
+ bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
+ bridge);
|
||||
+ if (WARN_ON(!bridge_state))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ret = bridge->funcs->atomic_check(bridge, bridge_state,
|
||||
+ crtc_state, conn_state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ } else if (bridge->funcs->mode_fixup) {
|
||||
+ if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode,
|
||||
+ &crtc_state->adjusted_mode))
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
|
||||
+ * @bridge: bridge control structure
|
||||
+ * @crtc_state: new CRTC state
|
||||
+ * @conn_state: new connector state
|
||||
+ *
|
||||
+ * Calls &drm_bridge_funcs.atomic_check() (falls back on
|
||||
+ * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
|
||||
+ * starting from the last bridge to the first. These are called before calling
|
||||
+ * &drm_encoder_helper_funcs.atomic_check()
|
||||
+ *
|
||||
+ * RETURNS:
|
||||
+ * 0 on success, a negative error code on failure
|
||||
+ */
|
||||
+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct drm_encoder *encoder;
|
||||
+ struct drm_bridge *iter;
|
||||
+
|
||||
+ if (!bridge)
|
||||
+ return 0;
|
||||
+
|
||||
+ encoder = bridge->encoder;
|
||||
+ list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (iter == bridge)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_bridge_chain_check);
|
||||
+
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_drm_find_bridge - find the bridge corresponding to the device node in
|
||||
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
|
||||
index df22f909141f..ff4df6eb2689 100644
|
||||
--- a/include/drm/drm_bridge.h
|
||||
+++ b/include/drm/drm_bridge.h
|
||||
@@ -111,7 +111,9 @@ struct drm_bridge_funcs {
|
||||
* this function passes all other callbacks must succeed for this
|
||||
* configuration.
|
||||
*
|
||||
- * The @mode_fixup callback is optional.
|
||||
+ * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup()
|
||||
+ * is not called when &drm_bridge_funcs.atomic_check() is implemented,
|
||||
+ * so only one of them should be provided.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
@@ -368,6 +370,28 @@ struct drm_bridge_funcs {
|
||||
void (*atomic_destroy_state)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state);
|
||||
|
||||
+ /**
|
||||
+ * @atomic_check:
|
||||
+ *
|
||||
+ * This method is responsible for checking bridge state correctness.
|
||||
+ * It can also check the state of the surrounding components in chain
|
||||
+ * to make sure the whole pipeline can work properly.
|
||||
+ *
|
||||
+ * &drm_bridge_funcs.atomic_check() hooks are called in reverse
|
||||
+ * order (from the last to the first bridge).
|
||||
+ *
|
||||
+ * This method is optional. &drm_bridge_funcs.mode_fixup() is not
|
||||
+ * called when &drm_bridge_funcs.atomic_check() is implemented, so only
|
||||
+ * one of them should be provided.
|
||||
+ *
|
||||
+ * RETURNS:
|
||||
+ * zero if the check passed, a negative error code otherwise.
|
||||
+ */
|
||||
+ int (*atomic_check)(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state);
|
||||
+
|
||||
/**
|
||||
* @atomic_reset:
|
||||
*
|
||||
@@ -542,6 +566,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
|
||||
void drm_bridge_chain_pre_enable(struct drm_bridge *bridge);
|
||||
void drm_bridge_chain_enable(struct drm_bridge *bridge);
|
||||
|
||||
+int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state);
|
||||
void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state);
|
||||
void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,614 +0,0 @@
|
||||
From 8d7c68f6f0e96b078bdeb81189ba0e8419a03dc8 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Mon, 6 Jan 2020 15:34:09 +0100
|
||||
Subject: [PATCH 084/146] FROMLIST: drm/bridge: Add the necessary bits to
|
||||
support bus format negotiation
|
||||
|
||||
drm_bridge_state is extended to describe the input and output bus
|
||||
configurations. These bus configurations are exposed through the
|
||||
drm_bus_cfg struct which encodes the configuration of a physical
|
||||
bus between two components in an output pipeline, usually between
|
||||
two bridges, an encoder and a bridge, or a bridge and a connector.
|
||||
|
||||
The bus configuration is stored in drm_bridge_state separately for
|
||||
the input and output buses, as seen from the point of view of each
|
||||
bridge. The bus configuration of a bridge output is usually identical
|
||||
to the configuration of the next bridge's input, but may differ if
|
||||
the signals are modified between the two bridges, for instance by an
|
||||
inverter on the board. The input and output configurations of a
|
||||
bridge may differ if the bridge modifies the signals internally,
|
||||
for instance by performing format conversion, or*modifying signals
|
||||
polarities.
|
||||
|
||||
Bus format negotiation is automated by the core, drivers just have
|
||||
to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they
|
||||
want to take part to this negotiation. Negotiation happens in reverse
|
||||
order, starting from the last element of the chain (the one directly
|
||||
connected to the display) up to the first element of the chain (the one
|
||||
connected to the encoder).
|
||||
During this negotiation all supported formats are tested until we find
|
||||
one that works, meaning that the formats array should be in decreasing
|
||||
preference order (assuming the driver has a preference order).
|
||||
|
||||
Note that the bus format negotiation works even if some elements in the
|
||||
chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks.
|
||||
In that case, the core advertises only MEDIA_BUS_FMT_FIXED and lets
|
||||
the previous bridge element decide what to do (most of the time, bridge
|
||||
drivers will pick a default bus format or extract this piece of
|
||||
information from somewhere else, like a FW property).
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v9:
|
||||
* No changes
|
||||
|
||||
v8:
|
||||
* Fix a test in drm_atomic_bridge_chain_select_bus_fmts() (Reported by
|
||||
Jonas)
|
||||
|
||||
v7:
|
||||
* Adapt the code to deal with the fact that not all bridges in the
|
||||
chain have a bridge state
|
||||
|
||||
v5 -> v6:
|
||||
* No changes
|
||||
|
||||
v4:
|
||||
* Enhance the doc
|
||||
* Fix typos
|
||||
* Rename some parameters/fields
|
||||
* Reword the commit message
|
||||
|
||||
v3:
|
||||
* Fix the commit message (Reported by Laurent)
|
||||
* Document the fact that bus formats should not be directly modified by
|
||||
drivers (Suggested by Laurent)
|
||||
* Document the fact that format order matters (Suggested by Laurent)
|
||||
* Propagate bus flags by default
|
||||
* Document the fact that drivers can tweak bus flags if needed
|
||||
* Let ->atomic_get_{output,input}_bus_fmts() allocate the bus format
|
||||
array (Suggested by Laurent)
|
||||
* Add a drm_atomic_helper_bridge_propagate_bus_fmt()
|
||||
* Mandate that bridge drivers return accurate input_fmts even if they
|
||||
are known to be the first element in the bridge chain
|
||||
|
||||
v2:
|
||||
* Rework things to support more complex use cases
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
[narmstrong: fixed doc in include/drm/drm_bridge.h:69 fmt->format]
|
||||
Reviewed by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Tested-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/drm_atomic_helper.c | 41 +++++
|
||||
drivers/gpu/drm/drm_bridge.c | 253 +++++++++++++++++++++++++++-
|
||||
include/drm/drm_atomic.h | 42 +++++
|
||||
include/drm/drm_atomic_helper.h | 8 +
|
||||
include/drm/drm_bridge.h | 82 +++++++++
|
||||
5 files changed, 425 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
index afe14f72a824..ea1926b5bb80 100644
|
||||
--- a/drivers/gpu/drm/drm_atomic_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_atomic_helper.c
|
||||
@@ -3528,3 +3528,44 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
|
||||
+
|
||||
+/**
|
||||
+ * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to
|
||||
+ * the input end of a bridge
|
||||
+ * @bridge: bridge control structure
|
||||
+ * @bridge_state: new bridge state
|
||||
+ * @crtc_state: new CRTC state
|
||||
+ * @conn_state: new connector state
|
||||
+ * @output_fmt: tested output bus format
|
||||
+ * @num_input_fmts: will contain the size of the returned array
|
||||
+ *
|
||||
+ * This helper is a pluggable implementation of the
|
||||
+ * &drm_bridge_funcs.atomic_get_input_bus_fmts operation for bridges that don't
|
||||
+ * modify the bus configuration between their input and their output. It
|
||||
+ * returns an array of input formats with a single element set to @output_fmt.
|
||||
+ *
|
||||
+ * RETURNS:
|
||||
+ * a valid format array of size @num_input_fmts, or NULL if the allocation
|
||||
+ * failed
|
||||
+ */
|
||||
+u32 *
|
||||
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts)
|
||||
+{
|
||||
+ u32 *input_fmts;
|
||||
+
|
||||
+ input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL);
|
||||
+ if (!input_fmts) {
|
||||
+ *num_input_fmts = 0;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ *num_input_fmts = 1;
|
||||
+ input_fmts[0] = output_fmt;
|
||||
+ return input_fmts;
|
||||
+}
|
||||
+EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
|
||||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
|
||||
index c8beb1385771..68ab933ee430 100644
|
||||
--- a/drivers/gpu/drm/drm_bridge.c
|
||||
+++ b/drivers/gpu/drm/drm_bridge.c
|
||||
@@ -628,13 +628,247 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int select_bus_fmt_recursive(struct drm_bridge *first_bridge,
|
||||
+ struct drm_bridge *cur_bridge,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 out_bus_fmt)
|
||||
+{
|
||||
+ struct drm_bridge_state *cur_state;
|
||||
+ unsigned int num_in_bus_fmts, i;
|
||||
+ struct drm_bridge *prev_bridge;
|
||||
+ u32 *in_bus_fmts;
|
||||
+ int ret;
|
||||
+
|
||||
+ prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
|
||||
+ cur_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
+ cur_bridge);
|
||||
+
|
||||
+ /*
|
||||
+ * If bus format negotiation is not supported by this bridge, let's
|
||||
+ * pass MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and
|
||||
+ * hope that it can handle this situation gracefully (by providing
|
||||
+ * appropriate default values).
|
||||
+ */
|
||||
+ if (!cur_bridge->funcs->atomic_get_input_bus_fmts) {
|
||||
+ if (cur_bridge != first_bridge) {
|
||||
+ ret = select_bus_fmt_recursive(first_bridge,
|
||||
+ prev_bridge, crtc_state,
|
||||
+ conn_state,
|
||||
+ MEDIA_BUS_FMT_FIXED);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Driver does not implement the atomic state hooks, but that's
|
||||
+ * fine, as long as it does not access the bridge state.
|
||||
+ */
|
||||
+ if (cur_state) {
|
||||
+ cur_state->input_bus_cfg.format = MEDIA_BUS_FMT_FIXED;
|
||||
+ cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If the driver implements ->atomic_get_input_bus_fmts() it
|
||||
+ * should also implement the atomic state hooks.
|
||||
+ */
|
||||
+ if (WARN_ON(!cur_state))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ in_bus_fmts = cur_bridge->funcs->atomic_get_input_bus_fmts(cur_bridge,
|
||||
+ cur_state,
|
||||
+ crtc_state,
|
||||
+ conn_state,
|
||||
+ out_bus_fmt,
|
||||
+ &num_in_bus_fmts);
|
||||
+ if (!num_in_bus_fmts)
|
||||
+ return -ENOTSUPP;
|
||||
+ else if (!in_bus_fmts)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (first_bridge == cur_bridge) {
|
||||
+ cur_state->input_bus_cfg.format = in_bus_fmts[0];
|
||||
+ cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
+ kfree(in_bus_fmts);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num_in_bus_fmts; i++) {
|
||||
+ ret = select_bus_fmt_recursive(first_bridge, prev_bridge,
|
||||
+ crtc_state, conn_state,
|
||||
+ in_bus_fmts[i]);
|
||||
+ if (ret != -ENOTSUPP)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!ret) {
|
||||
+ cur_state->input_bus_cfg.format = in_bus_fmts[i];
|
||||
+ cur_state->output_bus_cfg.format = out_bus_fmt;
|
||||
+ }
|
||||
+
|
||||
+ kfree(in_bus_fmts);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * This function is called by &drm_atomic_bridge_chain_check() just before
|
||||
+ * calling &drm_bridge_funcs.atomic_check() on all elements of the chain.
|
||||
+ * It performs bus format negotiation between bridge elements. The negotiation
|
||||
+ * happens in reverse order, starting from the last element in the chain up to
|
||||
+ * @bridge.
|
||||
+ *
|
||||
+ * Negotiation starts by retrieving supported output bus formats on the last
|
||||
+ * bridge element and testing them one by one. The test is recursive, meaning
|
||||
+ * that for each tested output format, the whole chain will be walked backward,
|
||||
+ * and each element will have to choose an input bus format that can be
|
||||
+ * transcoded to the requested output format. When a bridge element does not
|
||||
+ * support transcoding into a specific output format -ENOTSUPP is returned and
|
||||
+ * the next bridge element will have to try a different format. If none of the
|
||||
+ * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail.
|
||||
+ *
|
||||
+ * This implementation is relying on
|
||||
+ * &drm_bridge_funcs.atomic_get_output_bus_fmts() and
|
||||
+ * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported
|
||||
+ * input/output formats.
|
||||
+ *
|
||||
+ * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by
|
||||
+ * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts()
|
||||
+ * tries a single format: &drm_connector.display_info.bus_formats[0] if
|
||||
+ * available, MEDIA_BUS_FMT_FIXED otherwise.
|
||||
+ *
|
||||
+ * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented,
|
||||
+ * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the
|
||||
+ * bridge element that lacks this hook and asks the previous element in the
|
||||
+ * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what
|
||||
+ * to do in that case (fail if they want to enforce bus format negotiation, or
|
||||
+ * provide a reasonable default if they need to support pipelines where not
|
||||
+ * all elements support bus format negotiation).
|
||||
+ */
|
||||
+static int
|
||||
+drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct drm_connector *conn = conn_state->connector;
|
||||
+ struct drm_encoder *encoder = bridge->encoder;
|
||||
+ struct drm_bridge_state *last_bridge_state;
|
||||
+ unsigned int i, num_out_bus_fmts;
|
||||
+ struct drm_bridge *last_bridge;
|
||||
+ u32 *out_bus_fmts;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ last_bridge = list_last_entry(&encoder->bridge_chain,
|
||||
+ struct drm_bridge, chain_node);
|
||||
+ last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
+ last_bridge);
|
||||
+
|
||||
+ if (last_bridge->funcs->atomic_get_output_bus_fmts) {
|
||||
+ const struct drm_bridge_funcs *funcs = last_bridge->funcs;
|
||||
+
|
||||
+ /*
|
||||
+ * If the driver implements ->atomic_get_output_bus_fmts() it
|
||||
+ * should also implement the atomic state hooks.
|
||||
+ */
|
||||
+ if (WARN_ON(!last_bridge_state))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge,
|
||||
+ last_bridge_state,
|
||||
+ crtc_state,
|
||||
+ conn_state,
|
||||
+ &num_out_bus_fmts);
|
||||
+ if (!num_out_bus_fmts)
|
||||
+ return -ENOTSUPP;
|
||||
+ else if (!out_bus_fmts)
|
||||
+ return -ENOMEM;
|
||||
+ } else {
|
||||
+ num_out_bus_fmts = 1;
|
||||
+ out_bus_fmts = kmalloc(sizeof(*out_bus_fmts), GFP_KERNEL);
|
||||
+ if (!out_bus_fmts)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (conn->display_info.num_bus_formats &&
|
||||
+ conn->display_info.bus_formats)
|
||||
+ out_bus_fmts[0] = conn->display_info.bus_formats[0];
|
||||
+ else
|
||||
+ out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num_out_bus_fmts; i++) {
|
||||
+ ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
|
||||
+ conn_state, out_bus_fmts[i]);
|
||||
+ if (ret != -ENOTSUPP)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ kfree(out_bus_fmts);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge,
|
||||
+ struct drm_connector *conn,
|
||||
+ struct drm_atomic_state *state)
|
||||
+{
|
||||
+ struct drm_bridge_state *bridge_state, *next_bridge_state;
|
||||
+ struct drm_bridge *next_bridge;
|
||||
+ u32 output_flags = 0;
|
||||
+
|
||||
+ bridge_state = drm_atomic_get_new_bridge_state(state, bridge);
|
||||
+
|
||||
+ /* No bridge state attached to this bridge => nothing to propagate. */
|
||||
+ if (!bridge_state)
|
||||
+ return;
|
||||
+
|
||||
+ next_bridge = drm_bridge_get_next_bridge(bridge);
|
||||
+
|
||||
+ /*
|
||||
+ * Let's try to apply the most common case here, that is, propagate
|
||||
+ * display_info flags for the last bridge, and propagate the input
|
||||
+ * flags of the next bridge element to the output end of the current
|
||||
+ * bridge when the bridge is not the last one.
|
||||
+ * There are exceptions to this rule, like when signal inversion is
|
||||
+ * happening at the board level, but that's something drivers can deal
|
||||
+ * with from their &drm_bridge_funcs.atomic_check() implementation by
|
||||
+ * simply overriding the flags value we've set here.
|
||||
+ */
|
||||
+ if (!next_bridge) {
|
||||
+ output_flags = conn->display_info.bus_flags;
|
||||
+ } else {
|
||||
+ next_bridge_state = drm_atomic_get_new_bridge_state(state,
|
||||
+ next_bridge);
|
||||
+ /*
|
||||
+ * No bridge state attached to the next bridge, just leave the
|
||||
+ * flags to 0.
|
||||
+ */
|
||||
+ if (next_bridge_state)
|
||||
+ output_flags = next_bridge_state->input_bus_cfg.flags;
|
||||
+ }
|
||||
+
|
||||
+ bridge_state->output_bus_cfg.flags = output_flags;
|
||||
+
|
||||
+ /*
|
||||
+ * Propage the output flags to the input end of the bridge. Again, it's
|
||||
+ * not necessarily what all bridges want, but that's what most of them
|
||||
+ * do, and by doing that by default we avoid forcing drivers to
|
||||
+ * duplicate the "dummy propagation" logic.
|
||||
+ */
|
||||
+ bridge_state->input_bus_cfg.flags = output_flags;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain
|
||||
* @bridge: bridge control structure
|
||||
* @crtc_state: new CRTC state
|
||||
* @conn_state: new connector state
|
||||
*
|
||||
- * Calls &drm_bridge_funcs.atomic_check() (falls back on
|
||||
+ * First trigger a bus format negotiation before calling
|
||||
+ * &drm_bridge_funcs.atomic_check() (falls back on
|
||||
* &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain,
|
||||
* starting from the last bridge to the first. These are called before calling
|
||||
* &drm_encoder_helper_funcs.atomic_check()
|
||||
@@ -646,16 +880,33 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
+ struct drm_connector *conn = conn_state->connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge *iter;
|
||||
+ int ret;
|
||||
|
||||
if (!bridge)
|
||||
return 0;
|
||||
|
||||
+ ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state,
|
||||
+ conn_state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
encoder = bridge->encoder;
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
int ret;
|
||||
|
||||
+ /*
|
||||
+ * Bus flags are propagated by default. If a bridge needs to
|
||||
+ * tweak the input bus flags for any reason, it should happen
|
||||
+ * in its &drm_bridge_funcs.atomic_check() implementation such
|
||||
+ * that preceding bridges in the chain can propagate the new
|
||||
+ * bus flags.
|
||||
+ */
|
||||
+ drm_atomic_bridge_propagate_bus_flags(iter, conn,
|
||||
+ crtc_state->state);
|
||||
+
|
||||
ret = drm_atomic_bridge_check(iter, crtc_state, conn_state);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
|
||||
index 82a888769b3d..52d65a055491 100644
|
||||
--- a/include/drm/drm_atomic.h
|
||||
+++ b/include/drm/drm_atomic.h
|
||||
@@ -995,6 +995,38 @@ drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
|
||||
return state->active || state->self_refresh_active;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * struct drm_bus_cfg - bus configuration
|
||||
+ *
|
||||
+ * This structure stores the configuration of a physical bus between two
|
||||
+ * components in an output pipeline, usually between two bridges, an encoder
|
||||
+ * and a bridge, or a bridge and a connector.
|
||||
+ *
|
||||
+ * The bus configuration is stored in &drm_bridge_state separately for the
|
||||
+ * input and output buses, as seen from the point of view of each bridge. The
|
||||
+ * bus configuration of a bridge output is usually identical to the
|
||||
+ * configuration of the next bridge's input, but may differ if the signals are
|
||||
+ * modified between the two bridges, for instance by an inverter on the board.
|
||||
+ * The input and output configurations of a bridge may differ if the bridge
|
||||
+ * modifies the signals internally, for instance by performing format
|
||||
+ * conversion, or modifying signals polarities.
|
||||
+ */
|
||||
+struct drm_bus_cfg {
|
||||
+ /**
|
||||
+ * @format: format used on this bus (one of the MEDIA_BUS_FMT_* format)
|
||||
+ *
|
||||
+ * This field should not be directly modified by drivers
|
||||
+ * (&drm_atomic_bridge_chain_select_bus_fmts() takes care of the bus
|
||||
+ * format negotiation).
|
||||
+ */
|
||||
+ u32 format;
|
||||
+
|
||||
+ /**
|
||||
+ * @flags: DRM_BUS_* flags used on this bus
|
||||
+ */
|
||||
+ u32 flags;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct drm_bridge_state - Atomic bridge state object
|
||||
*/
|
||||
@@ -1008,6 +1040,16 @@ struct drm_bridge_state {
|
||||
* @bridge: the bridge this state refers to
|
||||
*/
|
||||
struct drm_bridge *bridge;
|
||||
+
|
||||
+ /**
|
||||
+ * @input_bus_cfg: input bus configuration
|
||||
+ */
|
||||
+ struct drm_bus_cfg input_bus_cfg;
|
||||
+
|
||||
+ /**
|
||||
+ * @output_bus_cfg: input bus configuration
|
||||
+ */
|
||||
+ struct drm_bus_cfg output_bus_cfg;
|
||||
};
|
||||
|
||||
static inline struct drm_bridge_state *
|
||||
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
|
||||
index 9db3cac48f4f..b268180c97eb 100644
|
||||
--- a/include/drm/drm_atomic_helper.h
|
||||
+++ b/include/drm/drm_atomic_helper.h
|
||||
@@ -224,4 +224,12 @@ drm_atomic_plane_disabling(struct drm_plane_state *old_plane_state,
|
||||
return old_plane_state->crtc && !new_plane_state->crtc;
|
||||
}
|
||||
|
||||
+u32 *
|
||||
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts);
|
||||
+
|
||||
#endif /* DRM_ATOMIC_HELPER_H_ */
|
||||
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
|
||||
index ff4df6eb2689..45626ecf20f8 100644
|
||||
--- a/include/drm/drm_bridge.h
|
||||
+++ b/include/drm/drm_bridge.h
|
||||
@@ -370,6 +370,72 @@ struct drm_bridge_funcs {
|
||||
void (*atomic_destroy_state)(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *state);
|
||||
|
||||
+ /**
|
||||
+ * @atomic_get_output_bus_fmts:
|
||||
+ *
|
||||
+ * Return the supported bus formats on the output end of a bridge.
|
||||
+ * The returned array must be allocated with kmalloc() and will be
|
||||
+ * freed by the caller. If the allocation fails, NULL should be
|
||||
+ * returned. num_output_fmts must be set to the returned array size.
|
||||
+ * Formats listed in the returned array should be listed in decreasing
|
||||
+ * preference order (the core will try all formats until it finds one
|
||||
+ * that works).
|
||||
+ *
|
||||
+ * This method is only called on the last element of the bridge chain
|
||||
+ * as part of the bus format negotiation process that happens in
|
||||
+ * &drm_atomic_bridge_chain_select_bus_fmts().
|
||||
+ * This method is optional. When not implemented, the core will
|
||||
+ * fall back to &drm_connector.display_info.bus_formats[0] if
|
||||
+ * &drm_connector.display_info.num_bus_formats > 0,
|
||||
+ * or to MEDIA_BUS_FMT_FIXED otherwise.
|
||||
+ */
|
||||
+ u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ unsigned int *num_output_fmts);
|
||||
+
|
||||
+ /**
|
||||
+ * @atomic_get_input_bus_fmts:
|
||||
+ *
|
||||
+ * Return the supported bus formats on the input end of a bridge for
|
||||
+ * a specific output bus format.
|
||||
+ *
|
||||
+ * The returned array must be allocated with kmalloc() and will be
|
||||
+ * freed by the caller. If the allocation fails, NULL should be
|
||||
+ * returned. num_output_fmts must be set to the returned array size.
|
||||
+ * Formats listed in the returned array should be listed in decreasing
|
||||
+ * preference order (the core will try all formats until it finds one
|
||||
+ * that works). When the format is not supported NULL should be
|
||||
+ * returned and *num_output_fmts should be set to 0.
|
||||
+ *
|
||||
+ * This method is called on all elements of the bridge chain as part of
|
||||
+ * the bus format negotiation process that happens in
|
||||
+ * &drm_atomic_bridge_chain_select_bus_fmts().
|
||||
+ * This method is optional. When not implemented, the core will bypass
|
||||
+ * bus format negotiation on this element of the bridge without
|
||||
+ * failing, and the previous element in the chain will be passed
|
||||
+ * MEDIA_BUS_FMT_FIXED as its output bus format.
|
||||
+ *
|
||||
+ * Bridge drivers that need to support being linked to bridges that are
|
||||
+ * not supporting bus format negotiation should handle the
|
||||
+ * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a
|
||||
+ * sensible default value or extracting this information from somewhere
|
||||
+ * else (FW property, &drm_display_mode, &drm_display_info, ...)
|
||||
+ *
|
||||
+ * Note: Even if input format selection on the first bridge has no
|
||||
+ * impact on the negotiation process (bus format negotiation stops once
|
||||
+ * we reach the first element of the chain), drivers are expected to
|
||||
+ * return accurate input formats as the input format may be used to
|
||||
+ * configure the CRTC output appropriately.
|
||||
+ */
|
||||
+ u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts);
|
||||
+
|
||||
/**
|
||||
* @atomic_check:
|
||||
*
|
||||
@@ -384,6 +450,14 @@ struct drm_bridge_funcs {
|
||||
* called when &drm_bridge_funcs.atomic_check() is implemented, so only
|
||||
* one of them should be provided.
|
||||
*
|
||||
+ * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or
|
||||
+ * &drm_bridge_state.output_bus_cfg.flags it should should happen in
|
||||
+ * this function. By default the &drm_bridge_state.output_bus_cfg.flags
|
||||
+ * field is set to the next bridge
|
||||
+ * &drm_bridge_state.input_bus_cfg.flags value or
|
||||
+ * &drm_connector.display_info.bus_flags if the bridge is the last
|
||||
+ * element in the chain.
|
||||
+ *
|
||||
* RETURNS:
|
||||
* zero if the check passed, a negative error code otherwise.
|
||||
*/
|
||||
@@ -578,6 +652,14 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
|
||||
void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_state *state);
|
||||
|
||||
+u32 *
|
||||
+drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts);
|
||||
+
|
||||
#ifdef CONFIG_DRM_PANEL_BRIDGE
|
||||
struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel);
|
||||
struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,304 +0,0 @@
|
||||
From 0f965c7cf688112d82449247551056f8c19e8d12 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Wed, 7 Aug 2019 17:46:37 +0200
|
||||
Subject: [PATCH 085/146] FROMLIST: drm/imx: pd: Use bus format/flags provided
|
||||
by the bridge when available
|
||||
|
||||
Now that bridges can expose the bus format/flags they expect, we can
|
||||
use those instead of the relying on the display_info provided by the
|
||||
connector (which is only valid if the encoder is directly connected
|
||||
to bridge element driving the panel/display).
|
||||
|
||||
We also explicitly expose the bus formats supported by our encoder by
|
||||
filling encoder->output_bus_caps with proper info.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
* Use kmalloc() instead of kcalloc()
|
||||
* Add a dev_warn() when unsupported flags are requested
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Add an imx_pd_format_supported() helper (suggested by Philipp)
|
||||
* Simplify imx_pd_bridge_atomic_get_output_bus_fmts() (suggested by Philipp)
|
||||
* Simplify imx_pd_bridge_atomic_get_input_bus_fmts()
|
||||
* Explicitly set the duplicate/destro_state() and reset() hooks
|
||||
|
||||
v4 -> v6:
|
||||
* Patch was not part of the series
|
||||
|
||||
v3 (all suggested by Philipp):
|
||||
* Adjust to match core changes
|
||||
* Propagate output format to input format
|
||||
* Pick a default value when output_fmt = _FIXED
|
||||
* Add missing BGR888 and GBR888 fmts to imx_pd_bus_fmts[]
|
||||
|
||||
v2:
|
||||
* Adjust things to match the new bus-format negotiation infra
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
---
|
||||
drivers/gpu/drm/imx/parallel-display.c | 177 +++++++++++++++++++++----
|
||||
1 file changed, 152 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
|
||||
index 3dca424059f7..dc05506b6d4b 100644
|
||||
--- a/drivers/gpu/drm/imx/parallel-display.c
|
||||
+++ b/drivers/gpu/drm/imx/parallel-display.c
|
||||
@@ -24,6 +24,7 @@
|
||||
struct imx_parallel_display {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
+ struct drm_bridge bridge;
|
||||
struct device *dev;
|
||||
void *edid;
|
||||
int edid_len;
|
||||
@@ -31,7 +32,7 @@ struct imx_parallel_display {
|
||||
u32 bus_flags;
|
||||
struct drm_display_mode mode;
|
||||
struct drm_panel *panel;
|
||||
- struct drm_bridge *bridge;
|
||||
+ struct drm_bridge *next_bridge;
|
||||
};
|
||||
|
||||
static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
|
||||
@@ -44,6 +45,11 @@ static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e)
|
||||
return container_of(e, struct imx_parallel_display, encoder);
|
||||
}
|
||||
|
||||
+static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
|
||||
+{
|
||||
+ return container_of(b, struct imx_parallel_display, bridge);
|
||||
+}
|
||||
+
|
||||
static int imx_pd_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
|
||||
@@ -89,37 +95,149 @@ static struct drm_encoder *imx_pd_connector_best_encoder(
|
||||
return &imxpd->encoder;
|
||||
}
|
||||
|
||||
-static void imx_pd_encoder_enable(struct drm_encoder *encoder)
|
||||
+static void imx_pd_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
- struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
|
||||
+ struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
|
||||
|
||||
drm_panel_prepare(imxpd->panel);
|
||||
drm_panel_enable(imxpd->panel);
|
||||
}
|
||||
|
||||
-static void imx_pd_encoder_disable(struct drm_encoder *encoder)
|
||||
+static void imx_pd_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
- struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
|
||||
+ struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
|
||||
|
||||
drm_panel_disable(imxpd->panel);
|
||||
drm_panel_unprepare(imxpd->panel);
|
||||
}
|
||||
|
||||
-static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
- struct drm_crtc_state *crtc_state,
|
||||
- struct drm_connector_state *conn_state)
|
||||
+static const u32 imx_pd_bus_fmts[] = {
|
||||
+ MEDIA_BUS_FMT_RGB888_1X24,
|
||||
+ MEDIA_BUS_FMT_BGR888_1X24,
|
||||
+ MEDIA_BUS_FMT_GBR888_1X24,
|
||||
+ MEDIA_BUS_FMT_RGB666_1X18,
|
||||
+ MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
|
||||
+ MEDIA_BUS_FMT_RGB565_1X16,
|
||||
+};
|
||||
+
|
||||
+static u32 *
|
||||
+imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ unsigned int *num_output_fmts)
|
||||
{
|
||||
- struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
|
||||
struct drm_display_info *di = &conn_state->connector->display_info;
|
||||
- struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
|
||||
+ struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
|
||||
+ u32 *output_fmts;
|
||||
|
||||
- if (!imxpd->bus_format && di->num_bus_formats) {
|
||||
- imx_crtc_state->bus_flags = di->bus_flags;
|
||||
- imx_crtc_state->bus_format = di->bus_formats[0];
|
||||
- } else {
|
||||
- imx_crtc_state->bus_flags = imxpd->bus_flags;
|
||||
- imx_crtc_state->bus_format = imxpd->bus_format;
|
||||
+ if (!imxpd->bus_format && !di->num_bus_formats) {
|
||||
+ *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
|
||||
+ return kmemdup(imx_pd_bus_fmts, sizeof(imx_pd_bus_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ }
|
||||
+
|
||||
+ *num_output_fmts = 1;
|
||||
+ output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
|
||||
+ if (!output_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!imxpd->bus_format && di->num_bus_formats)
|
||||
+ output_fmts[0] = di->bus_formats[0];
|
||||
+ else
|
||||
+ output_fmts[0] = imxpd->bus_format;
|
||||
+
|
||||
+ return output_fmts;
|
||||
+}
|
||||
+
|
||||
+static bool imx_pd_format_supported(u32 output_fmt)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) {
|
||||
+ if (imx_pd_bus_fmts[i] == output_fmt)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static u32 *
|
||||
+imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts)
|
||||
+{
|
||||
+ struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
|
||||
+ u32 *input_fmts;
|
||||
+
|
||||
+ /*
|
||||
+ * If the next bridge does not support bus format negotiation, let's
|
||||
+ * use the static bus format definition (imxpd->bus_format) if it's
|
||||
+ * specified, RGB888 when it's not.
|
||||
+ */
|
||||
+ if (output_fmt == MEDIA_BUS_FMT_FIXED)
|
||||
+ output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+
|
||||
+ /* Now make sure the requested output format is supported. */
|
||||
+ if ((imxpd->bus_format && imxpd->bus_format != output_fmt) ||
|
||||
+ !imx_pd_format_supported(output_fmt)) {
|
||||
+ *num_input_fmts = 0;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ *num_input_fmts = 1;
|
||||
+ input_fmts = kcalloc(*num_input_fmts, sizeof(*input_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!input_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ input_fmts[0] = output_fmt;
|
||||
+ return input_fmts;
|
||||
+}
|
||||
+
|
||||
+static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
|
||||
+ struct drm_display_info *di = &conn_state->connector->display_info;
|
||||
+ struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
|
||||
+ struct drm_bridge_state *next_bridge_state = NULL;
|
||||
+ struct drm_bridge *next_bridge;
|
||||
+ u32 bus_flags, bus_fmt;
|
||||
+
|
||||
+ next_bridge = drm_bridge_get_next_bridge(bridge);
|
||||
+ if (next_bridge)
|
||||
+ next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
|
||||
+ next_bridge);
|
||||
+
|
||||
+ if (next_bridge_state)
|
||||
+ bus_flags = next_bridge_state->input_bus_cfg.flags;
|
||||
+ else if (!imxpd->bus_format && di->num_bus_formats)
|
||||
+ bus_flags = di->bus_flags;
|
||||
+ else
|
||||
+ bus_flags = imxpd->bus_flags;
|
||||
+
|
||||
+ bus_fmt = bridge_state->input_bus_cfg.format;
|
||||
+ if (!imx_pd_format_supported(bus_fmt))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (bus_flags &
|
||||
+ ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH |
|
||||
+ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
|
||||
+ DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) {
|
||||
+ dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags);
|
||||
+ return -EINVAL;
|
||||
}
|
||||
+
|
||||
+ bridge_state->output_bus_cfg.flags = bus_flags;
|
||||
+ bridge_state->input_bus_cfg.flags = bus_flags;
|
||||
+ imx_crtc_state->bus_flags = bus_flags;
|
||||
+ imx_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
|
||||
imx_crtc_state->di_hsync_pin = 2;
|
||||
imx_crtc_state->di_vsync_pin = 3;
|
||||
|
||||
@@ -143,10 +261,15 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
|
||||
.destroy = imx_drm_encoder_destroy,
|
||||
};
|
||||
|
||||
-static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
|
||||
- .enable = imx_pd_encoder_enable,
|
||||
- .disable = imx_pd_encoder_disable,
|
||||
- .atomic_check = imx_pd_encoder_atomic_check,
|
||||
+static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
|
||||
+ .enable = imx_pd_bridge_enable,
|
||||
+ .disable = imx_pd_bridge_disable,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_check = imx_pd_bridge_atomic_check,
|
||||
+ .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts,
|
||||
+ .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
|
||||
};
|
||||
|
||||
static int imx_pd_register(struct drm_device *drm,
|
||||
@@ -166,11 +289,13 @@ static int imx_pd_register(struct drm_device *drm,
|
||||
*/
|
||||
imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
- drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs);
|
||||
drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs,
|
||||
DRM_MODE_ENCODER_NONE, NULL);
|
||||
|
||||
- if (!imxpd->bridge) {
|
||||
+ imxpd->bridge.funcs = &imx_pd_bridge_funcs;
|
||||
+ drm_bridge_attach(encoder, &imxpd->bridge, NULL);
|
||||
+
|
||||
+ if (!imxpd->next_bridge) {
|
||||
drm_connector_helper_add(&imxpd->connector,
|
||||
&imx_pd_connector_helper_funcs);
|
||||
drm_connector_init(drm, &imxpd->connector,
|
||||
@@ -181,8 +306,9 @@ static int imx_pd_register(struct drm_device *drm,
|
||||
if (imxpd->panel)
|
||||
drm_panel_attach(imxpd->panel, &imxpd->connector);
|
||||
|
||||
- if (imxpd->bridge) {
|
||||
- ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
|
||||
+ if (imxpd->next_bridge) {
|
||||
+ ret = drm_bridge_attach(encoder, imxpd->next_bridge,
|
||||
+ &imxpd->bridge);
|
||||
if (ret < 0) {
|
||||
dev_err(imxpd->dev, "failed to attach bridge: %d\n",
|
||||
ret);
|
||||
@@ -227,7 +353,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
|
||||
imxpd->bus_format = bus_format;
|
||||
|
||||
/* port@1 is the output port */
|
||||
- ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge);
|
||||
+ ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
|
||||
+ &imxpd->next_bridge);
|
||||
if (ret && ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,159 +0,0 @@
|
||||
From 9d32ba0831e5ca96e8575dc2b3f07d8cc0daf215 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Wed, 7 Aug 2019 17:50:10 +0200
|
||||
Subject: [PATCH 086/146] FROMLIST: drm/bridge: lvds-codec: Implement basic bus
|
||||
format negotiation
|
||||
|
||||
Some DPI -> LVDS encoders might support several input bus width. Add a
|
||||
DT property to describe the bus width used on a specific design.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Fix a use-after-release problem
|
||||
* Get rid of the data-mapping parsing
|
||||
* Use kmalloc instead of kcalloc.
|
||||
|
||||
v4 -> v6:
|
||||
* Not part of the series
|
||||
|
||||
v3:
|
||||
* Use bus-width for the rgb24/rgb18 distinction
|
||||
* Adjust code to match core changes
|
||||
* Get rid of of_get_data_mapping()
|
||||
* Don't implement ->atomic_check() (the core now takes care of bus
|
||||
flags propagation)
|
||||
|
||||
v2:
|
||||
* Make the bus-format negotiation logic more generic
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/lvds-codec.c | 64 ++++++++++++++++++++++++++---
|
||||
1 file changed, 58 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c
|
||||
index 5f04cc11227e..f4fd8472c335 100644
|
||||
--- a/drivers/gpu/drm/bridge/lvds-codec.c
|
||||
+++ b/drivers/gpu/drm/bridge/lvds-codec.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
+#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
@@ -19,6 +20,7 @@ struct lvds_codec {
|
||||
struct drm_bridge *panel_bridge;
|
||||
struct gpio_desc *powerdown_gpio;
|
||||
u32 connector_type;
|
||||
+ u32 input_fmt;
|
||||
};
|
||||
|
||||
static int lvds_codec_attach(struct drm_bridge *bridge)
|
||||
@@ -48,18 +50,47 @@ static void lvds_codec_disable(struct drm_bridge *bridge)
|
||||
gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 1);
|
||||
}
|
||||
|
||||
+static u32 *
|
||||
+lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts)
|
||||
+{
|
||||
+ struct lvds_codec *lvds_codec = container_of(bridge,
|
||||
+ struct lvds_codec, bridge);
|
||||
+ u32 *input_fmts;
|
||||
+
|
||||
+ input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
|
||||
+ if (!input_fmts) {
|
||||
+ *num_input_fmts = 0;
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ *num_input_fmts = 1;
|
||||
+ input_fmts[0] = lvds_codec->input_fmt;
|
||||
+ return input_fmts;
|
||||
+}
|
||||
+
|
||||
static struct drm_bridge_funcs funcs = {
|
||||
.attach = lvds_codec_attach,
|
||||
.enable = lvds_codec_enable,
|
||||
.disable = lvds_codec_disable,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_get_input_bus_fmts = lvds_codec_atomic_get_input_bus_fmts,
|
||||
};
|
||||
|
||||
static int lvds_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
- struct device_node *panel_node;
|
||||
+ struct device_node *np;
|
||||
struct drm_panel *panel;
|
||||
struct lvds_codec *lvds_codec;
|
||||
+ u32 input_bus_width;
|
||||
+ int err;
|
||||
|
||||
lvds_codec = devm_kzalloc(dev, sizeof(*lvds_codec), GFP_KERNEL);
|
||||
if (!lvds_codec)
|
||||
@@ -69,22 +100,43 @@ static int lvds_codec_probe(struct platform_device *pdev)
|
||||
lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(lvds_codec->powerdown_gpio)) {
|
||||
- int err = PTR_ERR(lvds_codec->powerdown_gpio);
|
||||
+ err = PTR_ERR(lvds_codec->powerdown_gpio);
|
||||
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(dev, "powerdown GPIO failure: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
+ np = of_graph_get_port_by_id(dev->of_node, 0);
|
||||
+ if (!np) {
|
||||
+ dev_dbg(dev, "port 0 not found\n");
|
||||
+ return -ENXIO;
|
||||
+ }
|
||||
+
|
||||
+ err = of_property_read_u32(np, "bus-width", &input_bus_width);
|
||||
+ of_node_put(np);
|
||||
+
|
||||
+ if (err) {
|
||||
+ lvds_codec->input_fmt = MEDIA_BUS_FMT_FIXED;
|
||||
+ } else if (input_bus_width == 18) {
|
||||
+ lvds_codec->input_fmt = MEDIA_BUS_FMT_RGB666_1X18;
|
||||
+ } else if (input_bus_width == 24) {
|
||||
+ lvds_codec->input_fmt = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+ } else {
|
||||
+ dev_dbg(dev, "unsupported bus-width value %u on port 0\n",
|
||||
+ input_bus_width);
|
||||
+ return -ENOTSUPP;
|
||||
+ }
|
||||
+
|
||||
/* Locate the panel DT node. */
|
||||
- panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
|
||||
- if (!panel_node) {
|
||||
+ np = of_graph_get_remote_node(dev->of_node, 1, 0);
|
||||
+ if (!np) {
|
||||
dev_dbg(dev, "panel DT node not found\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
- panel = of_drm_find_panel(panel_node);
|
||||
- of_node_put(panel_node);
|
||||
+ panel = of_drm_find_panel(np);
|
||||
+ of_node_put(np);
|
||||
if (IS_ERR(panel)) {
|
||||
dev_dbg(dev, "panel not found, deferring probe\n");
|
||||
return PTR_ERR(panel);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,53 +0,0 @@
|
||||
From f7ade7485c33634f315354ec9c9fe44e9bc1a764 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Tue, 22 Oct 2019 16:15:50 +0200
|
||||
Subject: [PATCH 087/146] FROMLIST: dt-bindings: display: bridge: lvds-codec:
|
||||
Add new bus-width prop
|
||||
|
||||
Add the bus-width property to describe the input bus format.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
* Add Rob's R-b
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Rebase on top of lvds-codec changes
|
||||
* Drop the data-mapping property
|
||||
|
||||
v4 -> v6:
|
||||
* Not part of the series
|
||||
|
||||
v3:
|
||||
* New patch
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||
---
|
||||
.../devicetree/bindings/display/bridge/lvds-codec.yaml | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
|
||||
index 8f373029f5d2..7c4e42f4de61 100644
|
||||
--- a/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
|
||||
+++ b/Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
|
||||
@@ -55,6 +55,14 @@ properties:
|
||||
description: |
|
||||
For LVDS encoders, port 0 is the parallel input
|
||||
For LVDS decoders, port 0 is the LVDS input
|
||||
+ properties:
|
||||
+ bus-width:
|
||||
+ allOf:
|
||||
+ - $ref: /schemas/types.yaml#/definitions/uint32
|
||||
+ - enum: [18, 24]
|
||||
+ - default: 24
|
||||
+ description:
|
||||
+ Number of data lines used to transmit the RGB data.
|
||||
|
||||
port@1:
|
||||
type: object
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,52 +0,0 @@
|
||||
From cc8eb0c850087b5f24b3dddb6ffe97204639057f Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Fri, 9 Aug 2019 21:41:29 +0200
|
||||
Subject: [PATCH 088/146] FROMLIST: drm/bridge: panel: Propage bus format/flags
|
||||
|
||||
So that the previous bridge element in the chain knows which input
|
||||
format the panel bridge expects.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* Set atomic state hooks explicitly
|
||||
|
||||
v4 -> v6:
|
||||
* Not part of the series
|
||||
|
||||
v3:
|
||||
* Adjust things to match the new bus-format negotiation approach
|
||||
* Use drm_atomic_helper_bridge_propagate_bus_fmt
|
||||
* Don't implement ->atomic_check() (the core now takes care of bus
|
||||
flags propagation)
|
||||
|
||||
v2:
|
||||
* Adjust things to match the new bus-format negotiation approach
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/panel.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
|
||||
index f66777e24968..dcc72bd7df30 100644
|
||||
--- a/drivers/gpu/drm/bridge/panel.c
|
||||
+++ b/drivers/gpu/drm/bridge/panel.c
|
||||
@@ -127,6 +127,10 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = {
|
||||
.enable = panel_bridge_enable,
|
||||
.disable = panel_bridge_disable,
|
||||
.post_disable = panel_bridge_post_disable,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
|
||||
};
|
||||
|
||||
/**
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,40 +0,0 @@
|
||||
From ee4a3484cef1cde1f1188c30f4bd39aeb7ceff35 Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Wed, 22 Jan 2020 10:32:06 +0100
|
||||
Subject: [PATCH 089/146] FROMLIST: drm/panel: simple: Fix the lt089ac29000
|
||||
bus_format
|
||||
|
||||
The lt089ac29000 panel is an LVDS panel, not a DPI one. Fix the
|
||||
definition to reflect this fact.
|
||||
|
||||
v10:
|
||||
* Add changelog to the commit message
|
||||
|
||||
v8 -> v9:
|
||||
* No changes
|
||||
|
||||
v7:
|
||||
* New patch
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
---
|
||||
drivers/gpu/drm/panel/panel-simple.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
|
||||
index e14c14ac62b5..17d3d8791da5 100644
|
||||
--- a/drivers/gpu/drm/panel/panel-simple.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-simple.c
|
||||
@@ -3023,7 +3023,7 @@ static const struct panel_desc toshiba_lt089ac29000 = {
|
||||
.width = 194,
|
||||
.height = 116,
|
||||
},
|
||||
- .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,64 +0,0 @@
|
||||
From ee156fec2cbc7610e71566d711031e6a52432b6d Mon Sep 17 00:00:00 2001
|
||||
From: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
Date: Wed, 7 Aug 2019 18:01:59 +0200
|
||||
Subject: [PATCH 090/146] FROMLIST: ARM: dts: imx: imx51-zii-rdu1: Fix the
|
||||
display pipeline definition
|
||||
|
||||
The current definition does not represent the exact display pipeline we
|
||||
have on the board: the LVDS panel is actually connected through a
|
||||
parallel -> LVDS bridge. Let's fix that so the driver can select the
|
||||
proper bus format on the CRTC end.
|
||||
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
---
|
||||
v2 -> v10:
|
||||
* No changes
|
||||
---
|
||||
arch/arm/boot/dts/imx51-zii-rdu1.dts | 24 +++++++++++++++++++++++-
|
||||
1 file changed, 23 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts
|
||||
index 3596060f52e7..3fb84ea7f993 100644
|
||||
--- a/arch/arm/boot/dts/imx51-zii-rdu1.dts
|
||||
+++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts
|
||||
@@ -95,6 +95,28 @@
|
||||
reg = <1>;
|
||||
|
||||
display_out: endpoint {
|
||||
+ remote-endpoint = <&lvds_encoder_in>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ lvds-encoder {
|
||||
+ compatible = "lvds-encoder";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ port@0 {
|
||||
+ reg = <0>;
|
||||
+ bus-width = <24>;
|
||||
+ lvds_encoder_in: endpoint {
|
||||
+ remote-endpoint = <&display_out>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ data-mapping = "jeida-24";
|
||||
+ lvds_encoder_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
@@ -110,7 +132,7 @@
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
- remote-endpoint = <&display_out>;
|
||||
+ remote-endpoint = <&lvds_encoder_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 8a53a0031c3cc251bd9f2ef59497b7838b8f0f3b Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 15 Dec 2019 17:02:24 +0000
|
||||
Subject: [PATCH 091/146] FROMLIST: drm/bridge: dw-hdmi: set mtmdsclock for
|
||||
deep color
|
||||
|
||||
Configure the correct mtmdsclock for deep colors to prepare support
|
||||
for 10, 12 & 16bit output.
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 67fca439bbfb..9e0927d22db6 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -1818,9 +1818,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
|
||||
|
||||
dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
|
||||
|
||||
+ if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
+ switch (hdmi_bus_fmt_color_depth(
|
||||
+ hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
+ case 16:
|
||||
+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 2;
|
||||
+ break;
|
||||
+ case 12:
|
||||
+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 3 / 2;
|
||||
+ break;
|
||||
+ case 10:
|
||||
+ vmode->mtmdsclock = (u64)vmode->mpixelclock * 5 / 4;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
|
||||
vmode->mtmdsclock /= 2;
|
||||
|
||||
+ dev_dbg(hdmi->dev, "final tmdsclk = %d\n", vmode->mtmdsclock);
|
||||
+
|
||||
/* Set up HDMI_FC_INVIDCONF */
|
||||
inv_val = (hdmi->hdmi_data.hdcp_enable ||
|
||||
(dw_hdmi_support_scdc(hdmi) &&
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,32 +0,0 @@
|
||||
From f3c6742cb0ac7a7b97a3b5a3896207ca8d6b5d5f Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 15 Dec 2019 17:02:24 +0000
|
||||
Subject: [PATCH 092/146] FROMLIST: drm/bridge: dw-hdmi: add max bpc connector
|
||||
property
|
||||
|
||||
Add the max_bpc property to the dw-hdmi connector to prepare support
|
||||
for 10, 12 & 16bit output support.
|
||||
|
||||
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 9e0927d22db6..051001f77dd4 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -2406,6 +2406,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
|
||||
DRM_MODE_CONNECTOR_HDMIA,
|
||||
hdmi->ddc);
|
||||
|
||||
+ drm_atomic_helper_connector_reset(connector);
|
||||
+
|
||||
+ drm_connector_attach_max_bpc_property(connector, 8, 16);
|
||||
+
|
||||
if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
|
||||
drm_object_attach_property(&connector->base,
|
||||
connector->dev->mode_config.hdr_output_metadata_property, 0);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,28 +0,0 @@
|
||||
From a58a3dacbd0015efc05c07021be26ba902e772c2 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 22 Jan 2020 17:00:41 +0100
|
||||
Subject: [PATCH 093/146] FROMLIST: drm/bridge: dw-hdmi: Plug atomic state
|
||||
hooks to the default implementation
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 051001f77dd4..fec4a4bcd1fe 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -2494,6 +2494,9 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.attach = dw_hdmi_bridge_attach,
|
||||
.detach = dw_hdmi_bridge_detach,
|
||||
.enable = dw_hdmi_bridge_enable,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,332 +0,0 @@
|
||||
From bf88a7d2e98e1d6874d0206430f210c20f5a8f69 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 13 Aug 2019 15:30:25 +0200
|
||||
Subject: [PATCH 094/146] FROMLIST: drm/bridge: synopsys: dw-hdmi: add bus
|
||||
format negociation
|
||||
|
||||
Add the atomic_get_output_bus_fmts, atomic_get_input_bus_fmts to negociate
|
||||
the possible output and input formats for the current mode and monitor,
|
||||
and use the negotiated formats in a basic atomic_check callback.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 272 +++++++++++++++++++++-
|
||||
1 file changed, 268 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index fec4a4bcd1fe..15048ad694bc 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -2095,11 +2095,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
|
||||
hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
|
||||
|
||||
- /* TOFIX: Get input format from plat data or fallback to RGB888 */
|
||||
if (hdmi->plat_data->input_bus_format)
|
||||
hdmi->hdmi_data.enc_in_bus_format =
|
||||
hdmi->plat_data->input_bus_format;
|
||||
- else
|
||||
+ else if (hdmi->hdmi_data.enc_in_bus_format == MEDIA_BUS_FMT_FIXED)
|
||||
hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
|
||||
/* TOFIX: Get input encoding from plat data or fallback to none */
|
||||
@@ -2109,8 +2108,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
else
|
||||
hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
|
||||
|
||||
- /* TOFIX: Default to RGB888 output format */
|
||||
- hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+ if (hdmi->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
|
||||
+ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
|
||||
hdmi->hdmi_data.pix_repet_factor = 0;
|
||||
hdmi->hdmi_data.hdcp_enable = 0;
|
||||
@@ -2388,6 +2387,267 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
|
||||
.atomic_check = dw_hdmi_connector_atomic_check,
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * Possible output formats :
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48,
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36,
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30,
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24,
|
||||
+ * - MEDIA_BUS_FMT_YUV16_1X48,
|
||||
+ * - MEDIA_BUS_FMT_RGB161616_1X48,
|
||||
+ * - MEDIA_BUS_FMT_UYVY12_1X24,
|
||||
+ * - MEDIA_BUS_FMT_YUV12_1X36,
|
||||
+ * - MEDIA_BUS_FMT_RGB121212_1X36,
|
||||
+ * - MEDIA_BUS_FMT_UYVY10_1X20,
|
||||
+ * - MEDIA_BUS_FMT_YUV10_1X30,
|
||||
+ * - MEDIA_BUS_FMT_RGB101010_1X30,
|
||||
+ * - MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
+ * - MEDIA_BUS_FMT_YUV8_1X24,
|
||||
+ * - MEDIA_BUS_FMT_RGB888_1X24,
|
||||
+ */
|
||||
+
|
||||
+/* Can return a maximum of 12 possible output formats for a mode/connector */
|
||||
+#define MAX_OUTPUT_SEL_FORMATS 12
|
||||
+
|
||||
+static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ unsigned int *num_output_fmts)
|
||||
+{
|
||||
+ struct drm_connector *conn = conn_state->connector;
|
||||
+ struct drm_display_info *info = &conn->display_info;
|
||||
+ struct drm_display_mode *mode = &crtc_state->mode;
|
||||
+ u8 max_bpc = conn_state->max_requested_bpc;
|
||||
+ bool is_hdmi2_sink = info->hdmi.scdc.supported ||
|
||||
+ (info->color_formats & DRM_COLOR_FORMAT_YCRCB420);
|
||||
+ u32 *output_fmts;
|
||||
+ int i = 0;
|
||||
+
|
||||
+ *num_output_fmts = 0;
|
||||
+
|
||||
+ output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!output_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ /*
|
||||
+ * If the current mode enforces 4:2:0, force the output but format
|
||||
+ * to 4:2:0 and do not add the YUV422/444/RGB formats
|
||||
+ */
|
||||
+ if (conn->ycbcr_420_allowed &&
|
||||
+ (drm_mode_is_420_only(info, mode) ||
|
||||
+ (is_hdmi2_sink && drm_mode_is_420_also(info, mode)))) {
|
||||
+
|
||||
+ /* Order bus formats from 16bit to 8bit if supported */
|
||||
+ if (max_bpc >= 16 && info->bpc == 16 &&
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY16_0_5X48;
|
||||
+
|
||||
+ if (max_bpc >= 12 && info->bpc >= 12 &&
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
|
||||
+
|
||||
+ if (max_bpc >= 10 && info->bpc >= 10 &&
|
||||
+ (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
|
||||
+
|
||||
+ /* Default 8bit fallback */
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
|
||||
+
|
||||
+ *num_output_fmts = i;
|
||||
+
|
||||
+ return output_fmts;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Order bus formats from 16bit to 8bit and from YUV422 to RGB
|
||||
+ * if supported. In any case the default RGB888 format is added
|
||||
+ */
|
||||
+
|
||||
+ if (max_bpc >= 16 && info->bpc == 16) {
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
||||
+
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
||||
+ }
|
||||
+
|
||||
+ if (max_bpc >= 12 && info->bpc >= 12) {
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
||||
+
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
||||
+
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
+ }
|
||||
+
|
||||
+ if (max_bpc >= 10 && info->bpc >= 10) {
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
||||
+
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
||||
+
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
+ }
|
||||
+
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
+
|
||||
+ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
+
|
||||
+ /* Default 8bit RGB fallback */
|
||||
+ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+
|
||||
+ *num_output_fmts = i;
|
||||
+
|
||||
+ return output_fmts;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Possible input formats :
|
||||
+ * - MEDIA_BUS_FMT_RGB888_1X24
|
||||
+ * - MEDIA_BUS_FMT_YUV8_1X24
|
||||
+ * - MEDIA_BUS_FMT_UYVY8_1X16
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY8_0_5X24
|
||||
+ * - MEDIA_BUS_FMT_RGB101010_1X30
|
||||
+ * - MEDIA_BUS_FMT_YUV10_1X30
|
||||
+ * - MEDIA_BUS_FMT_UYVY10_1X20
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY10_0_5X30
|
||||
+ * - MEDIA_BUS_FMT_RGB121212_1X36
|
||||
+ * - MEDIA_BUS_FMT_YUV12_1X36
|
||||
+ * - MEDIA_BUS_FMT_UYVY12_1X24
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY12_0_5X36
|
||||
+ * - MEDIA_BUS_FMT_RGB161616_1X48
|
||||
+ * - MEDIA_BUS_FMT_YUV16_1X48
|
||||
+ * - MEDIA_BUS_FMT_UYYVYY16_0_5X48
|
||||
+ */
|
||||
+
|
||||
+/* Can return a maximum of 4 possible input formats for an output format */
|
||||
+#define MAX_INPUT_SEL_FORMATS 4
|
||||
+
|
||||
+static u32 *dw_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts)
|
||||
+{
|
||||
+ u32 *input_fmts;
|
||||
+ int i = 0;
|
||||
+
|
||||
+ *num_input_fmts = 0;
|
||||
+
|
||||
+ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!input_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ switch (output_fmt) {
|
||||
+ /* 8bit */
|
||||
+ case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_YUV8_1X24:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_UYVY8_1X16:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
+ break;
|
||||
+
|
||||
+ /* 10bit */
|
||||
+ case MEDIA_BUS_FMT_RGB101010_1X30:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_YUV10_1X30:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_UYVY10_1X20:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30;
|
||||
+ break;
|
||||
+
|
||||
+ /* 12bit */
|
||||
+ case MEDIA_BUS_FMT_RGB121212_1X36:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_YUV12_1X36:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_UYVY12_1X24:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
|
||||
+ break;
|
||||
+
|
||||
+ /* 16bit */
|
||||
+ case MEDIA_BUS_FMT_RGB161616_1X48:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
||||
+ break;
|
||||
+ case MEDIA_BUS_FMT_YUV16_1X48:
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48;
|
||||
+ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48;
|
||||
+ break;
|
||||
+
|
||||
+ /* 420 */
|
||||
+ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
|
||||
+ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
|
||||
+ case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
|
||||
+ case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
|
||||
+ input_fmts[i++] = output_fmt;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ *num_input_fmts = i;
|
||||
+
|
||||
+ if (*num_input_fmts == 0) {
|
||||
+ kfree(input_fmts);
|
||||
+ input_fmts = NULL;
|
||||
+ }
|
||||
+
|
||||
+ return input_fmts;
|
||||
+}
|
||||
+
|
||||
+static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state)
|
||||
+{
|
||||
+ struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
+
|
||||
+ dev_dbg(hdmi->dev, "selected output format %x\n",
|
||||
+ bridge_state->output_bus_cfg.format);
|
||||
+
|
||||
+ hdmi->hdmi_data.enc_out_bus_format =
|
||||
+ bridge_state->output_bus_cfg.format;
|
||||
+
|
||||
+ dev_dbg(hdmi->dev, "selected input format %x\n",
|
||||
+ bridge_state->input_bus_cfg.format);
|
||||
+
|
||||
+ hdmi->hdmi_data.enc_in_bus_format =
|
||||
+ bridge_state->input_bus_cfg.format;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dw_hdmi *hdmi = bridge->driver_private;
|
||||
@@ -2499,6 +2759,9 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
|
||||
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.attach = dw_hdmi_bridge_attach,
|
||||
.detach = dw_hdmi_bridge_detach,
|
||||
+ .atomic_check = dw_hdmi_bridge_atomic_check,
|
||||
+ .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
|
||||
+ .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
|
||||
.enable = dw_hdmi_bridge_enable,
|
||||
.disable = dw_hdmi_bridge_disable,
|
||||
.mode_set = dw_hdmi_bridge_mode_set,
|
||||
@@ -2963,6 +3226,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
||||
|
||||
hdmi->bridge.driver_private = hdmi;
|
||||
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
|
||||
+
|
||||
#ifdef CONFIG_OF
|
||||
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||
#endif
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,49 +0,0 @@
|
||||
From 40136cc8c157433e269734d8ae45c77dbddb8272 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Nov 2018 17:39:46 +0100
|
||||
Subject: [PATCH 095/146] FROMLIST: drm/bridge: synopsys: dw-hdmi: allow
|
||||
ycbcr420 modes for >= 0x200a
|
||||
|
||||
Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support
|
||||
for these modes in the connector if the platform supports them.
|
||||
We limit these modes to DW-HDMI IP version >= 0x200a which
|
||||
are designed to support HDMI2.0 display modes.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++
|
||||
include/drm/bridge/dw_hdmi.h | 1 +
|
||||
2 files changed, 7 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 15048ad694bc..4b35ea1427df 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -3231,6 +3231,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
|
||||
hdmi->bridge.of_node = pdev->dev.of_node;
|
||||
#endif
|
||||
|
||||
+ if (hdmi->version >= 0x200a)
|
||||
+ hdmi->connector.ycbcr_420_allowed =
|
||||
+ hdmi->plat_data->ycbcr_420_allowed;
|
||||
+ else
|
||||
+ hdmi->connector.ycbcr_420_allowed = false;
|
||||
+
|
||||
memset(&pdevinfo, 0, sizeof(pdevinfo));
|
||||
pdevinfo.parent = dev;
|
||||
pdevinfo.id = PLATFORM_DEVID_AUTO;
|
||||
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
|
||||
index 9d4d5cc47969..0b34a12c4a1c 100644
|
||||
--- a/include/drm/bridge/dw_hdmi.h
|
||||
+++ b/include/drm/bridge/dw_hdmi.h
|
||||
@@ -129,6 +129,7 @@ struct dw_hdmi_plat_data {
|
||||
unsigned long input_bus_format;
|
||||
unsigned long input_bus_encoding;
|
||||
bool use_drm_infoframe;
|
||||
+ bool ycbcr_420_allowed;
|
||||
|
||||
/* Vendor PHY support */
|
||||
const struct dw_hdmi_phy_ops *phy_ops;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,44 +0,0 @@
|
||||
From 54b70a1b18ffd3cbc66023fbf4d240e702e9f689 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 13 Aug 2019 15:52:26 +0200
|
||||
Subject: [PATCH 096/146] FROMLIST: drm/meson: venc: make drm_display_mode
|
||||
const
|
||||
|
||||
Before switching to bridge funcs, make sure drm_display_mode is passed
|
||||
as const to the venc functions.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_venc.c | 2 +-
|
||||
drivers/gpu/drm/meson/meson_venc.h | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
index 4efd7864d5bf..a9ab78970bfe 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c
|
||||
@@ -946,7 +946,7 @@ bool meson_venc_hdmi_venc_repeat(int vic)
|
||||
EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
|
||||
|
||||
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
- struct drm_display_mode *mode)
|
||||
+ const struct drm_display_mode *mode)
|
||||
{
|
||||
union meson_hdmi_venc_mode *vmode = NULL;
|
||||
union meson_hdmi_venc_mode vmode_dmt;
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
|
||||
index 576768bdd08d..1abdcbdf51c0 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.h
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.h
|
||||
@@ -60,7 +60,7 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
|
||||
void meson_venci_cvbs_mode_set(struct meson_drm *priv,
|
||||
struct meson_cvbs_enci_mode *mode);
|
||||
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
- struct drm_display_mode *mode);
|
||||
+ const struct drm_display_mode *mode);
|
||||
unsigned int meson_venci_get_field(struct meson_drm *priv);
|
||||
|
||||
void meson_venc_enable_vsync(struct meson_drm *priv);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,230 +0,0 @@
|
||||
From fbf27a4e5d8aa254ec9c17a2556276cc4f1d519b Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 13 Aug 2019 15:30:25 +0200
|
||||
Subject: [PATCH 097/146] FROMLIST: drm/meson: meson_dw_hdmi: add bridge and
|
||||
switch to drm_bridge_funcs
|
||||
|
||||
Switch the dw-hdmi driver to drm_bridge_funcs by implementing a new local
|
||||
bridge, connecting it to the dw-hdmi bridge, then implement the
|
||||
atomic_get_input_bus_fmts/atomic_get_output_bus_fmts.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 105 +++++++++++++++++++++-----
|
||||
1 file changed, 85 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index 3bb7ffe5fc39..4b3809626f7e 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
+#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
@@ -135,6 +136,7 @@ struct meson_dw_hdmi_data {
|
||||
|
||||
struct meson_dw_hdmi {
|
||||
struct drm_encoder encoder;
|
||||
+ struct drm_bridge bridge;
|
||||
struct dw_hdmi_plat_data dw_plat_data;
|
||||
struct meson_drm *priv;
|
||||
struct device *dev;
|
||||
@@ -151,6 +153,8 @@ struct meson_dw_hdmi {
|
||||
};
|
||||
#define encoder_to_meson_dw_hdmi(x) \
|
||||
container_of(x, struct meson_dw_hdmi, encoder)
|
||||
+#define bridge_to_meson_dw_hdmi(x) \
|
||||
+ container_of(x, struct meson_dw_hdmi, bridge)
|
||||
|
||||
static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
|
||||
const char *compat)
|
||||
@@ -368,7 +372,7 @@ static inline void meson_dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
|
||||
}
|
||||
|
||||
static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
- struct drm_display_mode *mode)
|
||||
+ const struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
@@ -663,6 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
/* Encoder */
|
||||
|
||||
+static const u32 meson_dw_hdmi_out_bus_fmts[] = {
|
||||
+ MEDIA_BUS_FMT_YUV8_1X24,
|
||||
+};
|
||||
+
|
||||
static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
drm_encoder_cleanup(encoder);
|
||||
@@ -672,16 +680,63 @@ static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
|
||||
.destroy = meson_venc_hdmi_encoder_destroy,
|
||||
};
|
||||
|
||||
-static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
+static u32 *
|
||||
+meson_venc_hdmi_encoder_get_out_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ unsigned int *num_output_fmts)
|
||||
+{
|
||||
+ u32 *output_fmts;
|
||||
+
|
||||
+ *num_output_fmts = ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts);
|
||||
+ output_fmts = kcalloc(*num_output_fmts, sizeof(*output_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!output_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ memcpy(output_fmts, meson_dw_hdmi_out_bus_fmts, *num_output_fmts);
|
||||
+
|
||||
+ return output_fmts;
|
||||
+}
|
||||
+
|
||||
+static u32 *
|
||||
+meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
+ struct drm_crtc_state *crtc_state,
|
||||
+ struct drm_connector_state *conn_state,
|
||||
+ u32 output_fmt,
|
||||
+ unsigned int *num_input_fmts)
|
||||
+{
|
||||
+ u32 *input_fmts = NULL;
|
||||
+
|
||||
+ if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
|
||||
+ *num_input_fmts = 1;
|
||||
+ input_fmts = kcalloc(*num_input_fmts,
|
||||
+ sizeof(*input_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!input_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ input_fmts[0] = output_fmt;
|
||||
+ } else {
|
||||
+ *num_input_fmts = 0;
|
||||
+ }
|
||||
+
|
||||
+ return input_fmts;
|
||||
+}
|
||||
+
|
||||
+static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
|
||||
+ struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
+static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
- struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
+ struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
@@ -693,9 +748,9 @@ static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
|
||||
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
}
|
||||
|
||||
-static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
+static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
- struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
+ struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
|
||||
@@ -706,11 +761,11 @@ static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
|
||||
writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
|
||||
}
|
||||
|
||||
-static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
- struct drm_display_mode *mode,
|
||||
- struct drm_display_mode *adjusted_mode)
|
||||
+static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
|
||||
+ const struct drm_display_mode *mode,
|
||||
+ const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
- struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
|
||||
+ struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
|
||||
@@ -726,12 +781,16 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
|
||||
writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
|
||||
}
|
||||
|
||||
-static const struct drm_encoder_helper_funcs
|
||||
- meson_venc_hdmi_encoder_helper_funcs = {
|
||||
- .atomic_check = meson_venc_hdmi_encoder_atomic_check,
|
||||
- .disable = meson_venc_hdmi_encoder_disable,
|
||||
- .enable = meson_venc_hdmi_encoder_enable,
|
||||
- .mode_set = meson_venc_hdmi_encoder_mode_set,
|
||||
+static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
|
||||
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
+ .atomic_get_output_bus_fmts = meson_venc_hdmi_encoder_get_out_bus_fmts,
|
||||
+ .atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts,
|
||||
+ .atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
+ .atomic_check = meson_venc_hdmi_encoder_atomic_check,
|
||||
+ .enable = meson_venc_hdmi_encoder_enable,
|
||||
+ .disable = meson_venc_hdmi_encoder_disable,
|
||||
+ .mode_set = meson_venc_hdmi_encoder_mode_set,
|
||||
};
|
||||
|
||||
/* DW HDMI Regmap */
|
||||
@@ -852,6 +911,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
struct drm_device *drm = data;
|
||||
struct meson_drm *priv = drm->dev_private;
|
||||
struct dw_hdmi_plat_data *dw_plat_data;
|
||||
+ struct drm_bridge *next_bridge;
|
||||
struct drm_encoder *encoder;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
@@ -953,8 +1013,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
|
||||
/* Encoder */
|
||||
|
||||
- drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
|
||||
-
|
||||
ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS, "meson_hdmi");
|
||||
if (ret) {
|
||||
@@ -962,6 +1020,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs;
|
||||
+ drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL);
|
||||
+
|
||||
encoder->possible_crtcs = BIT(0);
|
||||
|
||||
DRM_DEBUG_DRIVER("encoder initialized\n");
|
||||
@@ -984,11 +1045,15 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
|
||||
platform_set_drvdata(pdev, meson_dw_hdmi);
|
||||
|
||||
- meson_dw_hdmi->hdmi = dw_hdmi_bind(pdev, encoder,
|
||||
- &meson_dw_hdmi->dw_plat_data);
|
||||
+ meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev,
|
||||
+ &meson_dw_hdmi->dw_plat_data);
|
||||
if (IS_ERR(meson_dw_hdmi->hdmi))
|
||||
return PTR_ERR(meson_dw_hdmi->hdmi);
|
||||
|
||||
+ next_bridge = of_drm_find_bridge(pdev->dev.of_node);
|
||||
+ if (next_bridge)
|
||||
+ drm_bridge_attach(encoder, next_bridge, &meson_dw_hdmi->bridge);
|
||||
+
|
||||
DRM_DEBUG_DRIVER("HDMI controller initialized\n");
|
||||
|
||||
return 0;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,30 +0,0 @@
|
||||
From fbffdc84fa2b464b209a6944e0ab32c8bb496ae7 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 13 Aug 2019 16:21:27 +0200
|
||||
Subject: [PATCH 098/146] FROMLIST: drm/meson: dw-hdmi: stop enforcing
|
||||
input_bus_format
|
||||
|
||||
To allow using formats from negotiation, stop enforcing input_bus_format
|
||||
in the private dw-plat-data struct.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index 4b3809626f7e..686c47106a18 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -1035,7 +1035,6 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
|
||||
dw_plat_data->phy_name = "meson_dw_hdmi_phy";
|
||||
dw_plat_data->phy_data = meson_dw_hdmi;
|
||||
- dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
|
||||
dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
|
||||
|
||||
if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,85 +0,0 @@
|
||||
From 1473862349ce78372db09e20c9154654ff1196f9 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Aug 2019 10:48:21 +0200
|
||||
Subject: [PATCH 099/146] FROMLIST: drm/meson: venc: add support for YUV420
|
||||
setup
|
||||
|
||||
This patch adds encoding support for the YUV420 output from the
|
||||
Amlogic Meson SoCs Video Processing Unit to the HDMI Controller.
|
||||
|
||||
The YUV420 is obtained by generating a YUV444 pixel stream like
|
||||
the classic HDMI display modes, but then the Video Encoder output
|
||||
can be configured to down-sample the YUV444 pixel stream to a YUV420
|
||||
stream.
|
||||
|
||||
In addition if pixel stream down-sampling, the Y Cb Cr components must
|
||||
also be mapped differently to align with the HDMI2.0 specifications.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 3 ++-
|
||||
drivers/gpu/drm/meson/meson_venc.c | 8 +++++---
|
||||
drivers/gpu/drm/meson/meson_venc.h | 2 ++
|
||||
3 files changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index 686c47106a18..f5d46d082534 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -772,7 +772,8 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
|
||||
DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
|
||||
|
||||
/* VENC + VENC-DVI Mode setup */
|
||||
- meson_venc_hdmi_mode_set(priv, vic, mode);
|
||||
+ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, false,
|
||||
+ VPU_HDMI_OUTPUT_CBYCR);
|
||||
|
||||
/* VCLK Set clock */
|
||||
dw_hdmi_set_vclk(dw_hdmi, mode);
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
index a9ab78970bfe..f93c725b6f02 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c
|
||||
@@ -946,6 +946,8 @@ bool meson_venc_hdmi_venc_repeat(int vic)
|
||||
EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
|
||||
|
||||
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
+ unsigned int ycrcb_map,
|
||||
+ bool yuv420_mode,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
union meson_hdmi_venc_mode *vmode = NULL;
|
||||
@@ -1528,14 +1530,14 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
reg |= VPU_HDMI_INV_VSYNC;
|
||||
|
||||
- /* Output data format: CbYCr */
|
||||
- reg |= VPU_HDMI_OUTPUT_CBYCR;
|
||||
+ /* Output data format */
|
||||
+ reg |= ycrcb_map;
|
||||
|
||||
/*
|
||||
* Write rate to the async FIFO between VENC and HDMI.
|
||||
* One write every 2 wr_clk.
|
||||
*/
|
||||
- if (venc_repeat)
|
||||
+ if (venc_repeat || yuv420_mode)
|
||||
reg |= VPU_HDMI_WR_RATE(2);
|
||||
|
||||
/*
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
|
||||
index 1abdcbdf51c0..9138255ffc9e 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.h
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.h
|
||||
@@ -60,6 +60,8 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
|
||||
void meson_venci_cvbs_mode_set(struct meson_drm *priv,
|
||||
struct meson_cvbs_enci_mode *mode);
|
||||
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
+ unsigned int ycrcb_map,
|
||||
+ bool yuv420_mode,
|
||||
const struct drm_display_mode *mode);
|
||||
unsigned int meson_venci_get_field(struct meson_drm *priv);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,363 +0,0 @@
|
||||
From 355bab871c74d2c2b3cf233292506cf3cf8fcfac Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Aug 2019 10:52:52 +0200
|
||||
Subject: [PATCH 100/146] FROMLIST: drm/meson: vclk: add support for YUV420
|
||||
setup
|
||||
|
||||
This patch adds clocking support for the YUV420 output from the
|
||||
Amlogic Meson SoCs Video Processing Unit to the HDMI Controller.
|
||||
|
||||
The YUV420 is obtained by generating a YUV444 pixel stream like
|
||||
the classic HDMI display modes, but then the Video Encoder output
|
||||
can be configured to down-sample the YUV444 pixel stream to a YUV420
|
||||
stream.
|
||||
|
||||
This mode needs a different clock generation scheme since the TMDS PHY
|
||||
clock must match the 10x ratio with the YUV420 pixel clock, but
|
||||
the video encoder must run at 2x the pixel clock.
|
||||
|
||||
This patch adds the TMDS PHY clock value in all the video clock setup
|
||||
in order to better support these specific uses cases and switch
|
||||
to the Common Clock framework for clocks handling in the future.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 24 ++++---
|
||||
drivers/gpu/drm/meson/meson_vclk.c | 93 +++++++++++++++++++------
|
||||
drivers/gpu/drm/meson/meson_vclk.h | 7 +-
|
||||
drivers/gpu/drm/meson/meson_venc_cvbs.c | 6 +-
|
||||
4 files changed, 95 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index f5d46d082534..94f206bf795d 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -376,15 +376,19 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
{
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
+ unsigned int phy_freq;
|
||||
unsigned int vclk_freq;
|
||||
unsigned int venc_freq;
|
||||
unsigned int hdmi_freq;
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
+ /* TMDS clock is pixel_clock * 10 */
|
||||
+ phy_freq = vclk_freq * 10;
|
||||
+
|
||||
if (!vic) {
|
||||
- meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
|
||||
- vclk_freq, vclk_freq, false);
|
||||
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
|
||||
+ vclk_freq, vclk_freq, vclk_freq, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -402,11 +406,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
venc_freq /= 2;
|
||||
|
||||
- DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
|
||||
- vclk_freq, venc_freq, hdmi_freq,
|
||||
+ DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
|
||||
+ phy_freq, vclk_freq, venc_freq, hdmi_freq,
|
||||
priv->venc.hdmi_use_enci);
|
||||
|
||||
- meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
|
||||
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
|
||||
venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
|
||||
}
|
||||
|
||||
@@ -617,6 +621,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_drm *priv = connector->dev->dev_private;
|
||||
+ unsigned int phy_freq;
|
||||
unsigned int vclk_freq;
|
||||
unsigned int venc_freq;
|
||||
unsigned int hdmi_freq;
|
||||
@@ -643,6 +648,9 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
+ /* TMDS clock is pixel_clock * 10 */
|
||||
+ phy_freq = vclk_freq * 10;
|
||||
+
|
||||
/* 480i/576i needs global pixel doubling */
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
vclk_freq *= 2;
|
||||
@@ -659,10 +667,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
venc_freq /= 2;
|
||||
|
||||
- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
|
||||
- vclk_freq, venc_freq, hdmi_freq);
|
||||
+ dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
|
||||
+ __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
|
||||
|
||||
- return meson_vclk_vic_supported_freq(vclk_freq);
|
||||
+ return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
|
||||
}
|
||||
|
||||
/* Encoder */
|
||||
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
index f690793ae2d5..fdf26dac9fa8 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
@@ -354,12 +354,17 @@ enum {
|
||||
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
|
||||
MESON_VCLK_HDMI_297000,
|
||||
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
|
||||
- MESON_VCLK_HDMI_594000
|
||||
+ MESON_VCLK_HDMI_594000,
|
||||
+/* 2970 /1 /1 /1 /5 /1 => /1 /2 */
|
||||
+ MESON_VCLK_HDMI_594000_YUV420,
|
||||
};
|
||||
|
||||
struct meson_vclk_params {
|
||||
+ unsigned int pll_freq;
|
||||
+ unsigned int phy_freq;
|
||||
+ unsigned int vclk_freq;
|
||||
+ unsigned int venc_freq;
|
||||
unsigned int pixel_freq;
|
||||
- unsigned int pll_base_freq;
|
||||
unsigned int pll_od1;
|
||||
unsigned int pll_od2;
|
||||
unsigned int pll_od3;
|
||||
@@ -367,8 +372,11 @@ struct meson_vclk_params {
|
||||
unsigned int vclk_div;
|
||||
} params[] = {
|
||||
[MESON_VCLK_HDMI_ENCI_54000] = {
|
||||
+ .pll_freq = 4320000,
|
||||
+ .phy_freq = 270000,
|
||||
+ .vclk_freq = 54000,
|
||||
+ .venc_freq = 54000,
|
||||
.pixel_freq = 54000,
|
||||
- .pll_base_freq = 4320000,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 4,
|
||||
.pll_od3 = 1,
|
||||
@@ -376,8 +384,11 @@ struct meson_vclk_params {
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_DDR_54000] = {
|
||||
- .pixel_freq = 54000,
|
||||
- .pll_base_freq = 4320000,
|
||||
+ .pll_freq = 4320000,
|
||||
+ .phy_freq = 270000,
|
||||
+ .vclk_freq = 54000,
|
||||
+ .venc_freq = 54000,
|
||||
+ .pixel_freq = 27000,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 4,
|
||||
.pll_od3 = 1,
|
||||
@@ -385,8 +396,11 @@ struct meson_vclk_params {
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_DDR_148500] = {
|
||||
- .pixel_freq = 148500,
|
||||
- .pll_base_freq = 2970000,
|
||||
+ .pll_freq = 2970000,
|
||||
+ .phy_freq = 742500,
|
||||
+ .vclk_freq = 148500,
|
||||
+ .venc_freq = 148500,
|
||||
+ .pixel_freq = 74250,
|
||||
.pll_od1 = 4,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 1,
|
||||
@@ -394,8 +408,11 @@ struct meson_vclk_params {
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_74250] = {
|
||||
+ .pll_freq = 2970000,
|
||||
+ .phy_freq = 742500,
|
||||
+ .vclk_freq = 74250,
|
||||
+ .venc_freq = 74250,
|
||||
.pixel_freq = 74250,
|
||||
- .pll_base_freq = 2970000,
|
||||
.pll_od1 = 2,
|
||||
.pll_od2 = 2,
|
||||
.pll_od3 = 2,
|
||||
@@ -403,8 +420,11 @@ struct meson_vclk_params {
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_148500] = {
|
||||
+ .pll_freq = 2970000,
|
||||
+ .phy_freq = 1485000,
|
||||
+ .vclk_freq = 148500,
|
||||
+ .venc_freq = 148500,
|
||||
.pixel_freq = 148500,
|
||||
- .pll_base_freq = 2970000,
|
||||
.pll_od1 = 1,
|
||||
.pll_od2 = 2,
|
||||
.pll_od3 = 2,
|
||||
@@ -412,8 +432,11 @@ struct meson_vclk_params {
|
||||
.vclk_div = 1,
|
||||
},
|
||||
[MESON_VCLK_HDMI_297000] = {
|
||||
+ .pll_freq = 5940000,
|
||||
+ .phy_freq = 2970000,
|
||||
+ .venc_freq = 297000,
|
||||
+ .vclk_freq = 297000,
|
||||
.pixel_freq = 297000,
|
||||
- .pll_base_freq = 5940000,
|
||||
.pll_od1 = 2,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 1,
|
||||
@@ -421,14 +444,29 @@ struct meson_vclk_params {
|
||||
.vclk_div = 2,
|
||||
},
|
||||
[MESON_VCLK_HDMI_594000] = {
|
||||
+ .pll_freq = 5940000,
|
||||
+ .phy_freq = 5940000,
|
||||
+ .venc_freq = 594000,
|
||||
+ .vclk_freq = 594000,
|
||||
.pixel_freq = 594000,
|
||||
- .pll_base_freq = 5940000,
|
||||
.pll_od1 = 1,
|
||||
.pll_od2 = 1,
|
||||
.pll_od3 = 2,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 1,
|
||||
},
|
||||
+ [MESON_VCLK_HDMI_594000_YUV420] = {
|
||||
+ .pll_freq = 5940000,
|
||||
+ .phy_freq = 2970000,
|
||||
+ .venc_freq = 594000,
|
||||
+ .vclk_freq = 594000,
|
||||
+ .pixel_freq = 297000,
|
||||
+ .pll_od1 = 2,
|
||||
+ .pll_od2 = 1,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 1,
|
||||
+ },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
@@ -701,6 +739,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
|
||||
unsigned int od, m, frac, od1, od2, od3;
|
||||
|
||||
if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
|
||||
+ /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */
|
||||
od3 = 1;
|
||||
if (od < 4) {
|
||||
od1 = 2;
|
||||
@@ -723,21 +762,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
|
||||
}
|
||||
|
||||
enum drm_mode_status
|
||||
-meson_vclk_vic_supported_freq(unsigned int freq)
|
||||
+meson_vclk_vic_supported_freq(unsigned int phy_freq,
|
||||
+ unsigned int vclk_freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
- DRM_DEBUG_DRIVER("freq = %d\n", freq);
|
||||
+ DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
|
||||
+ phy_freq, vclk_freq);
|
||||
|
||||
for (i = 0 ; params[i].pixel_freq ; ++i) {
|
||||
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
|
||||
i, params[i].pixel_freq,
|
||||
FREQ_1000_1001(params[i].pixel_freq));
|
||||
+ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
|
||||
+ i, params[i].phy_freq,
|
||||
+ FREQ_1000_1001(params[i].phy_freq/10)*10);
|
||||
/* Match strict frequency */
|
||||
- if (freq == params[i].pixel_freq)
|
||||
+ if (phy_freq == params[i].phy_freq &&
|
||||
+ vclk_freq == params[i].vclk_freq)
|
||||
return MODE_OK;
|
||||
/* Match 1000/1001 variant */
|
||||
- if (freq == FREQ_1000_1001(params[i].pixel_freq))
|
||||
+ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
|
||||
+ vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
@@ -965,8 +1011,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
|
||||
}
|
||||
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
- unsigned int vclk_freq, unsigned int venc_freq,
|
||||
- unsigned int dac_freq, bool hdmi_use_enci)
|
||||
+ unsigned int phy_freq, unsigned int vclk_freq,
|
||||
+ unsigned int venc_freq, unsigned int dac_freq,
|
||||
+ bool hdmi_use_enci)
|
||||
{
|
||||
bool vic_alternate_clock = false;
|
||||
unsigned int freq;
|
||||
@@ -986,7 +1033,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
* - venc_div = 1
|
||||
* - encp encoder
|
||||
*/
|
||||
- meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
|
||||
+ meson_vclk_set(priv, phy_freq, 0, 0, 0,
|
||||
VID_PLL_DIV_5, 2, 1, 1, false, false);
|
||||
return;
|
||||
}
|
||||
@@ -1008,9 +1055,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
}
|
||||
|
||||
for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
|
||||
- if (vclk_freq == params[freq].pixel_freq ||
|
||||
- vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
|
||||
- if (vclk_freq != params[freq].pixel_freq)
|
||||
+ if ((phy_freq == params[freq].phy_freq ||
|
||||
+ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
|
||||
+ (vclk_freq == params[freq].vclk_freq ||
|
||||
+ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
|
||||
+ if (vclk_freq != params[freq].vclk_freq)
|
||||
vic_alternate_clock = true;
|
||||
else
|
||||
vic_alternate_clock = false;
|
||||
@@ -1039,7 +1088,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
return;
|
||||
}
|
||||
|
||||
- meson_vclk_set(priv, params[freq].pll_base_freq,
|
||||
+ meson_vclk_set(priv, params[freq].pll_freq,
|
||||
params[freq].pll_od1, params[freq].pll_od2,
|
||||
params[freq].pll_od3, params[freq].vid_pll_div,
|
||||
params[freq].vclk_div, hdmi_tx_div, venc_div,
|
||||
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
|
||||
index b62125540aef..aed0ab2efa71 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.h
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.h
|
||||
@@ -25,10 +25,11 @@ enum {
|
||||
enum drm_mode_status
|
||||
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
|
||||
enum drm_mode_status
|
||||
-meson_vclk_vic_supported_freq(unsigned int freq);
|
||||
+meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
|
||||
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
- unsigned int vclk_freq, unsigned int venc_freq,
|
||||
- unsigned int dac_freq, bool hdmi_use_enci);
|
||||
+ unsigned int phy_freq, unsigned int vclk_freq,
|
||||
+ unsigned int venc_freq, unsigned int dac_freq,
|
||||
+ bool hdmi_use_enci);
|
||||
|
||||
#endif /* __MESON_VCLK_H */
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
|
||||
index 1bd6b6d15ffb..541f9eb2a135 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
|
||||
@@ -213,8 +213,10 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
|
||||
meson_venci_cvbs_mode_set(priv, meson_mode->enci);
|
||||
|
||||
/* Setup 27MHz vclk2 for ENCI and VDAC */
|
||||
- meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS,
|
||||
- MESON_VCLK_CVBS, MESON_VCLK_CVBS, true);
|
||||
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
|
||||
+ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
|
||||
+ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
|
||||
+ true);
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,240 +0,0 @@
|
||||
From 225a0abd39d8620ceb98f1fa920b849cb916185c Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 15 Nov 2018 16:41:23 +0100
|
||||
Subject: [PATCH 101/146] FROMLIST: drm/meson: Add YUV420 output support
|
||||
|
||||
This patch adds support for the YUV420 output from the Amlogic Meson SoCs
|
||||
Video Processing Unit to the HDMI Controller.
|
||||
|
||||
The YUV420 is obtained by generating a YUV444 pixel stream like
|
||||
the classic HDMI display modes, but then the Video Encoder output
|
||||
can be configured to down-sample the YUV444 pixel stream to a YUV420
|
||||
stream.
|
||||
In addition if pixel stream down-sampling, the Y Cb Cr components must
|
||||
also be mapped differently to align with the HDMI2.0 specifications.
|
||||
|
||||
This mode needs a different clock generation scheme since the TMDS PHY
|
||||
clock must match the 10x ration with the YUV420 pixel clock, but
|
||||
the video encoder must run at 2x the pixel clock.
|
||||
|
||||
This patch enables the bridge bus format negociation, and handles
|
||||
the YUV420 case if selected by the negociation.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 91 ++++++++++++++++++++-------
|
||||
1 file changed, 70 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index 94f206bf795d..5962afbfc8ab 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -150,6 +150,7 @@ struct meson_dw_hdmi {
|
||||
struct regulator *hdmi_supply;
|
||||
u32 irq_stat;
|
||||
struct dw_hdmi *hdmi;
|
||||
+ unsigned long output_bus_fmt;
|
||||
};
|
||||
#define encoder_to_meson_dw_hdmi(x) \
|
||||
container_of(x, struct meson_dw_hdmi, encoder)
|
||||
@@ -301,6 +302,10 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
unsigned int pixel_clock = mode->clock;
|
||||
|
||||
+ /* For 420, pixel clock is half unlike venc clock */
|
||||
+ if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
|
||||
+ pixel_clock /= 2;
|
||||
+
|
||||
if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
|
||||
if (pixel_clock >= 371250) {
|
||||
@@ -383,6 +388,10 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
+ /* For 420, pixel clock is half unlike venc clock */
|
||||
+ if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
|
||||
+ vclk_freq /= 2;
|
||||
+
|
||||
/* TMDS clock is pixel_clock * 10 */
|
||||
phy_freq = vclk_freq * 10;
|
||||
|
||||
@@ -392,13 +401,16 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
|
||||
return;
|
||||
}
|
||||
|
||||
+ /* 480i/576i needs global pixel doubling */
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
|
||||
vclk_freq *= 2;
|
||||
|
||||
venc_freq = vclk_freq;
|
||||
hdmi_freq = vclk_freq;
|
||||
|
||||
- if (meson_venc_hdmi_venc_repeat(vic))
|
||||
+ /* VENC double pixels for 1080i, 720p and YUV420 modes */
|
||||
+ if (meson_venc_hdmi_venc_repeat(vic) ||
|
||||
+ dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
|
||||
venc_freq *= 2;
|
||||
|
||||
vclk_freq = max(venc_freq, hdmi_freq);
|
||||
@@ -445,8 +457,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
|
||||
/* Enable normal output to PHY */
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
|
||||
|
||||
- /* TMDS pattern setup (TOFIX Handle the YUV420 case) */
|
||||
- if (mode->clock > 340000) {
|
||||
+ /* TMDS pattern setup */
|
||||
+ if (mode->clock > 340000 &&
|
||||
+ dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_YUV8_1X24) {
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
|
||||
0);
|
||||
dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
|
||||
@@ -621,6 +634,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct meson_drm *priv = connector->dev->dev_private;
|
||||
+ bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
|
||||
unsigned int phy_freq;
|
||||
unsigned int vclk_freq;
|
||||
unsigned int venc_freq;
|
||||
@@ -630,9 +644,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
|
||||
|
||||
- /* If sink max TMDS clock, we reject the mode */
|
||||
+ /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */
|
||||
if (connector->display_info.max_tmds_clock &&
|
||||
- mode->clock > connector->display_info.max_tmds_clock)
|
||||
+ mode->clock > connector->display_info.max_tmds_clock &&
|
||||
+ !drm_mode_is_420_only(&connector->display_info, mode) &&
|
||||
+ !drm_mode_is_420_also(&connector->display_info, mode))
|
||||
return MODE_BAD;
|
||||
|
||||
/* Check against non-VIC supported modes */
|
||||
@@ -648,6 +664,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
vclk_freq = mode->clock;
|
||||
|
||||
+ /* For 420, pixel clock is half unlike venc clock */
|
||||
+ if (drm_mode_is_420_only(&connector->display_info, mode) ||
|
||||
+ (!is_hdmi2_sink &&
|
||||
+ drm_mode_is_420_also(&connector->display_info, mode)))
|
||||
+ vclk_freq /= 2;
|
||||
+
|
||||
/* TMDS clock is pixel_clock * 10 */
|
||||
phy_freq = vclk_freq * 10;
|
||||
|
||||
@@ -658,8 +680,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
venc_freq = vclk_freq;
|
||||
hdmi_freq = vclk_freq;
|
||||
|
||||
- /* VENC double pixels for 1080i and 720p modes */
|
||||
- if (meson_venc_hdmi_venc_repeat(vic))
|
||||
+ /* VENC double pixels for 1080i, 720p and YUV420 modes */
|
||||
+ if (meson_venc_hdmi_venc_repeat(vic) ||
|
||||
+ drm_mode_is_420_only(&connector->display_info, mode) ||
|
||||
+ (!is_hdmi2_sink &&
|
||||
+ drm_mode_is_420_also(&connector->display_info, mode)))
|
||||
venc_freq *= 2;
|
||||
|
||||
vclk_freq = max(venc_freq, hdmi_freq);
|
||||
@@ -677,6 +702,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
static const u32 meson_dw_hdmi_out_bus_fmts[] = {
|
||||
MEDIA_BUS_FMT_YUV8_1X24,
|
||||
+ MEDIA_BUS_FMT_UYYVYY8_0_5X24,
|
||||
};
|
||||
|
||||
static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
|
||||
@@ -717,18 +743,23 @@ meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge,
|
||||
unsigned int *num_input_fmts)
|
||||
{
|
||||
u32 *input_fmts = NULL;
|
||||
+ int i;
|
||||
|
||||
- if (output_fmt == meson_dw_hdmi_out_bus_fmts[0]) {
|
||||
- *num_input_fmts = 1;
|
||||
- input_fmts = kcalloc(*num_input_fmts,
|
||||
- sizeof(*input_fmts),
|
||||
- GFP_KERNEL);
|
||||
- if (!input_fmts)
|
||||
- return NULL;
|
||||
+ *num_input_fmts = 0;
|
||||
|
||||
- input_fmts[0] = output_fmt;
|
||||
- } else {
|
||||
- *num_input_fmts = 0;
|
||||
+ for (i = 0 ; i < ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts) ; ++i) {
|
||||
+ if (output_fmt == meson_dw_hdmi_out_bus_fmts[i]) {
|
||||
+ *num_input_fmts = 1;
|
||||
+ input_fmts = kcalloc(*num_input_fmts,
|
||||
+ sizeof(*input_fmts),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!input_fmts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ input_fmts[0] = output_fmt;
|
||||
+
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
|
||||
return input_fmts;
|
||||
@@ -739,6 +770,12 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
+ struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
|
||||
+
|
||||
+ dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format;
|
||||
+
|
||||
+ DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -776,18 +813,29 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge,
|
||||
struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge);
|
||||
struct meson_drm *priv = dw_hdmi->priv;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
+ unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR;
|
||||
+ bool yuv420_mode = false;
|
||||
|
||||
DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic);
|
||||
|
||||
+ if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
|
||||
+ ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
|
||||
+ yuv420_mode = true;
|
||||
+ }
|
||||
+
|
||||
/* VENC + VENC-DVI Mode setup */
|
||||
- meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, false,
|
||||
- VPU_HDMI_OUTPUT_CBYCR);
|
||||
+ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode);
|
||||
|
||||
/* VCLK Set clock */
|
||||
dw_hdmi_set_vclk(dw_hdmi, mode);
|
||||
|
||||
- /* Setup YUV444 to HDMI-TX, no 10bit diphering */
|
||||
- writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
|
||||
+ if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
|
||||
+ /* Setup YUV420 to HDMI-TX, no 10bit diphering */
|
||||
+ writel_relaxed(2 | (2 << 2),
|
||||
+ priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
|
||||
+ else
|
||||
+ /* Setup YUV444 to HDMI-TX, no 10bit diphering */
|
||||
+ writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = {
|
||||
@@ -1045,6 +1093,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
|
||||
dw_plat_data->phy_name = "meson_dw_hdmi_phy";
|
||||
dw_plat_data->phy_data = meson_dw_hdmi;
|
||||
dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
|
||||
+ dw_plat_data->ycbcr_420_allowed = true;
|
||||
|
||||
if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
|
||||
dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") ||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,77 +0,0 @@
|
||||
From 523fe0901b9522abe6fc951d12dbb94e730ad3da Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Sun, 1 Mar 2020 16:45:34 +0000
|
||||
Subject: [PATCH 102/146] FROMLIST: drm/bridge: dw-hdmi: fix AVI frame
|
||||
colorimetry
|
||||
|
||||
CTA-861-F explicitly states that for RGB colorspace colorimetry should
|
||||
be set to "none". Fix that.
|
||||
|
||||
Fixes: def23aa7e982 ("drm: bridge: dw-hdmi: Switch to V4L bus format and encodings")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 46 +++++++++++++----------
|
||||
1 file changed, 26 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 4b35ea1427df..2115b13676cb 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -1624,28 +1624,34 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
frame.colorspace = HDMI_COLORSPACE_RGB;
|
||||
|
||||
/* Set up colorimetry */
|
||||
- switch (hdmi->hdmi_data.enc_out_encoding) {
|
||||
- case V4L2_YCBCR_ENC_601:
|
||||
- if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
|
||||
- frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
|
||||
- else
|
||||
+ if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
+ switch (hdmi->hdmi_data.enc_out_encoding) {
|
||||
+ case V4L2_YCBCR_ENC_601:
|
||||
+ if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
|
||||
+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
|
||||
+ else
|
||||
+ frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
|
||||
+ frame.extended_colorimetry =
|
||||
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
||||
+ break;
|
||||
+ case V4L2_YCBCR_ENC_709:
|
||||
+ if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
|
||||
+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
|
||||
+ else
|
||||
+ frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
|
||||
+ frame.extended_colorimetry =
|
||||
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
|
||||
+ break;
|
||||
+ default: /* Carries no data */
|
||||
frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
|
||||
+ frame.extended_colorimetry =
|
||||
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ frame.colorimetry = HDMI_COLORIMETRY_NONE;
|
||||
frame.extended_colorimetry =
|
||||
- HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
||||
- break;
|
||||
- case V4L2_YCBCR_ENC_709:
|
||||
- if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
|
||||
- frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
|
||||
- else
|
||||
- frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
|
||||
- frame.extended_colorimetry =
|
||||
- HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
|
||||
- break;
|
||||
- default: /* Carries no data */
|
||||
- frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
|
||||
- frame.extended_colorimetry =
|
||||
- HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
||||
- break;
|
||||
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
|
||||
}
|
||||
|
||||
frame.scan_mode = HDMI_SCAN_MODE_NONE;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,36 +0,0 @@
|
||||
From 3816853f9ea2c93c27f462a030f5446b5f7613a5 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Sun, 1 Mar 2020 16:46:34 +0000
|
||||
Subject: [PATCH 103/146] FROMLIST: drm/bridge: dw-hdmi: Fix color space
|
||||
conversion detection
|
||||
|
||||
Currently, is_color_space_conversion() compares not only color spaces
|
||||
but also formats. For example, function would return true if YCbCr 4:4:4
|
||||
and YCbCr 4:2:2 would be set. Obviously in that case color spaces are
|
||||
the same.
|
||||
|
||||
Fix that by comparing if both values represent RGB color space.
|
||||
|
||||
Fixes: b21f4b658df8 ("drm: imx: imx-hdmi: move imx-hdmi to bridge/dw_hdmi")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 2115b13676cb..97e5eb0e81cd 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -956,7 +956,8 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
|
||||
|
||||
static int is_color_space_conversion(struct dw_hdmi *hdmi)
|
||||
{
|
||||
- return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format;
|
||||
+ return hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) !=
|
||||
+ hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format);
|
||||
}
|
||||
|
||||
static int is_color_space_decimation(struct dw_hdmi *hdmi)
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,115 +0,0 @@
|
||||
From 6160df65923ea72b35531490a989b8e07a708539 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Sun, 1 Mar 2020 16:55:05 +0000
|
||||
Subject: [PATCH 105/146] FROMLIST: drm/bridge: dw-hdmi: Add support for RGB
|
||||
limited range
|
||||
|
||||
CEA 861 standard request that RGB quantization range is "limited" for
|
||||
CEA modes. Support that by adding CSC matrix which downscales values.
|
||||
|
||||
This allows to proper color reproduction on TV and PC monitor at the
|
||||
same time. In future, override property can be added, like "Broadcast
|
||||
RGB" in i915 driver.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 36 +++++++++++++++++++++--
|
||||
1 file changed, 34 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 664e3c5cd5b5..1103be760fd5 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -92,6 +92,12 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
|
||||
{ 0x6756, 0x78ab, 0x2000, 0x0200 }
|
||||
};
|
||||
|
||||
+static const u16 csc_coeff_rgb_limited[3][4] = {
|
||||
+ { 0x1B7C, 0x0000, 0x0000, 0x0020 },
|
||||
+ { 0x0000, 0x1B7C, 0x0000, 0x0020 },
|
||||
+ { 0x0000, 0x0000, 0x1B7C, 0x0020 }
|
||||
+};
|
||||
+
|
||||
struct hdmi_vmode {
|
||||
bool mdataenablepolarity;
|
||||
|
||||
@@ -109,6 +115,7 @@ struct hdmi_data_info {
|
||||
unsigned int pix_repet_factor;
|
||||
unsigned int hdcp_enable;
|
||||
struct hdmi_vmode video_mode;
|
||||
+ bool rgb_limited_range;
|
||||
};
|
||||
|
||||
struct dw_hdmi_i2c {
|
||||
@@ -960,6 +967,13 @@ static int is_color_space_conversion(struct dw_hdmi *hdmi)
|
||||
hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format);
|
||||
}
|
||||
|
||||
+static int is_rgb_downscale_needed(struct dw_hdmi *hdmi)
|
||||
+{
|
||||
+ return hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) &&
|
||||
+ hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) &&
|
||||
+ hdmi->hdmi_data.rgb_limited_range;
|
||||
+}
|
||||
+
|
||||
static int is_color_space_decimation(struct dw_hdmi *hdmi)
|
||||
{
|
||||
if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
|
||||
@@ -1006,6 +1020,8 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
|
||||
csc_coeff = &csc_coeff_rgb_in_eitu709;
|
||||
csc_scale = 0;
|
||||
}
|
||||
+ } else if (is_rgb_downscale_needed(hdmi)) {
|
||||
+ csc_coeff = &csc_coeff_rgb_limited;
|
||||
}
|
||||
|
||||
/* The CSC registers are sequential, alternating MSB then LSB */
|
||||
@@ -1615,6 +1631,18 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&frame,
|
||||
&hdmi->connector, mode);
|
||||
|
||||
+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
|
||||
+ drm_hdmi_avi_infoframe_quant_range(&frame, &hdmi->connector,
|
||||
+ mode,
|
||||
+ hdmi->hdmi_data.rgb_limited_range ?
|
||||
+ HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||
+ HDMI_QUANTIZATION_RANGE_FULL);
|
||||
+ } else {
|
||||
+ frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
|
||||
+ frame.ycc_quantization_range =
|
||||
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
|
||||
+ }
|
||||
+
|
||||
if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
|
||||
frame.colorspace = HDMI_COLORSPACE_YUV444;
|
||||
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
|
||||
@@ -2007,13 +2035,13 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
|
||||
hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
|
||||
|
||||
/* Enable csc path */
|
||||
- if (is_color_space_conversion(hdmi)) {
|
||||
+ if (is_color_space_conversion(hdmi) || is_rgb_downscale_needed(hdmi)) {
|
||||
hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
|
||||
hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
|
||||
}
|
||||
|
||||
/* Enable color space conversion if needed */
|
||||
- if (is_color_space_conversion(hdmi))
|
||||
+ if (is_color_space_conversion(hdmi) || is_rgb_downscale_needed(hdmi))
|
||||
hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
|
||||
HDMI_MC_FLOWCTRL);
|
||||
else
|
||||
@@ -2116,6 +2144,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||
if (hdmi->hdmi_data.enc_out_bus_format == MEDIA_BUS_FMT_FIXED)
|
||||
hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
|
||||
+ hdmi->hdmi_data.rgb_limited_range = hdmi->sink_is_hdmi &&
|
||||
+ drm_default_rgb_quant_range(mode) ==
|
||||
+ HDMI_QUANTIZATION_RANGE_LIMITED;
|
||||
+
|
||||
hdmi->hdmi_data.pix_repet_factor = 0;
|
||||
hdmi->hdmi_data.hdcp_enable = 0;
|
||||
hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,387 +0,0 @@
|
||||
From dc3637389ac69c219bb4321677b1647cd5645a9b Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 6 Dec 2019 16:23:23 +0100
|
||||
Subject: [PATCH 106/146] FROMLIST: media: v4l2-mem2mem: handle draining,
|
||||
stopped and next-buf-is-last states
|
||||
|
||||
Since the draining and stop phase of the HW decoder mem2mem bahaviour is
|
||||
now clearly defined, we can move handling of the following states to the
|
||||
common v4l2-mem2mem core code:
|
||||
- draining
|
||||
- stopped
|
||||
- next-buf-is-last
|
||||
|
||||
By introducing the following v4l2-mem2mem APIS:
|
||||
- v4l2_m2m_encoder_cmd/v4l2_m2m_ioctl_encoder_cmd to handle start/stop command
|
||||
- v4l2_m2m_decoder_cmd/v4l2_m2m_ioctl_decoder_cmd to handle start/stop command
|
||||
- v4l2_m2m_start_streaming to handle start of streaming of the de/encoder queue
|
||||
- v4l2_m2m_stop_streaming to handle stop of streaming of the de/encoder queue
|
||||
- v4l2_m2m_last_buffer_done to maek the current dest buffer as the last one
|
||||
|
||||
And inline helpers:
|
||||
- v4l2_m2m_mark_stopped to mark the de/encoding process as stopped
|
||||
- v4l2_m2m_clear_state to clear the de/encoding state
|
||||
- v4l2_m2m_dst_buf_is_last to detect the current dequeud dst_buf is the last
|
||||
- v4l2_m2m_has_stopped to detect the de/encoding stopped state
|
||||
- v4l2_m2m_is_last_draining_src_buf to detect the currect source buffer should
|
||||
be the last processing before stopping the de/encoding process
|
||||
|
||||
The special next-buf-is-last when min_buffers != 1 case is also handled
|
||||
in v4l2_m2m_qbuf() by reusing the other introduced APIs.
|
||||
|
||||
This state management has been stolen from the vicodec implementation,
|
||||
and is no-op for drivers not calling the v4l2_m2m_encoder_cmd or
|
||||
v4l2_m2m_decoder_cmd and v4l2_m2m_start_streaming/v4l2_m2m_stop_streaming.
|
||||
|
||||
The vicodec will be the first one to be converted as an example.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-mem2mem.c | 172 ++++++++++++++++++++++++-
|
||||
include/media/v4l2-mem2mem.h | 95 ++++++++++++++
|
||||
2 files changed, 265 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
|
||||
index 1afd9c6ad908..f221d6c7a137 100644
|
||||
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
|
||||
@@ -340,6 +340,11 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev,
|
||||
m2m_ctx->new_frame = !dst->vb2_buf.copied_timestamp ||
|
||||
dst->vb2_buf.timestamp != src->vb2_buf.timestamp;
|
||||
|
||||
+ if (m2m_ctx->has_stopped) {
|
||||
+ dprintk("Device has stopped\n");
|
||||
+ goto job_unlock;
|
||||
+ }
|
||||
+
|
||||
if (m2m_dev->m2m_ops->job_ready
|
||||
&& (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
|
||||
dprintk("Driver not ready\n");
|
||||
@@ -556,6 +561,99 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
|
||||
|
||||
+void v4l2_m2m_last_buffer_done(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_v4l2_buffer *vbuf)
|
||||
+{
|
||||
+ vbuf->flags |= V4L2_BUF_FLAG_LAST;
|
||||
+ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
|
||||
+
|
||||
+ v4l2_m2m_mark_stopped(m2m_ctx);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_last_buffer_done);
|
||||
+
|
||||
+static int v4l2_mark_last_buf(struct v4l2_m2m_ctx *m2m_ctx)
|
||||
+{
|
||||
+ struct vb2_v4l2_buffer *next_dst_buf;
|
||||
+
|
||||
+ if (m2m_ctx->is_draining)
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ if (m2m_ctx->has_stopped)
|
||||
+ return 0;
|
||||
+
|
||||
+ m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx);
|
||||
+ m2m_ctx->is_draining = true;
|
||||
+
|
||||
+ if (m2m_ctx->last_src_buf)
|
||||
+ return 0;
|
||||
+
|
||||
+ next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
|
||||
+ if (!next_dst_buf) {
|
||||
+ m2m_ctx->next_buf_last = true;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ v4l2_m2m_last_buffer_done(m2m_ctx, next_dst_buf);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void v4l2_m2m_start_streaming(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_queue *q)
|
||||
+{
|
||||
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
|
||||
+ m2m_ctx->last_src_buf = NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_start_streaming);
|
||||
+
|
||||
+void v4l2_m2m_stop_streaming(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_queue *q)
|
||||
+{
|
||||
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
|
||||
+ if (m2m_ctx->is_draining) {
|
||||
+ struct vb2_v4l2_buffer *next_dst_buf;
|
||||
+
|
||||
+ m2m_ctx->last_src_buf = NULL;
|
||||
+ next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
|
||||
+ if (!next_dst_buf)
|
||||
+ m2m_ctx->next_buf_last = true;
|
||||
+ else
|
||||
+ v4l2_m2m_last_buffer_done(m2m_ctx,
|
||||
+ next_dst_buf);
|
||||
+ }
|
||||
+ } else {
|
||||
+ v4l2_m2m_clear_state(m2m_ctx);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_stop_streaming);
|
||||
+
|
||||
+static void v4l2_m2m_force_last_buf_done(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_queue *q)
|
||||
+{
|
||||
+ struct vb2_buffer *vb;
|
||||
+ struct vb2_v4l2_buffer *vbuf;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ if (WARN_ON(q->is_output))
|
||||
+ return;
|
||||
+ if (list_empty(&q->queued_list))
|
||||
+ return;
|
||||
+
|
||||
+ vb = list_first_entry(&q->queued_list, struct vb2_buffer, queued_entry);
|
||||
+ for (i = 0; i < vb->num_planes; i++)
|
||||
+ vb2_set_plane_payload(vb, i, 0);
|
||||
+
|
||||
+ /*
|
||||
+ * Since the buffer hasn't been queued to the ready queue,
|
||||
+ * mark is active and owned before marking it LAST and DONE
|
||||
+ */
|
||||
+ vb->state = VB2_BUF_STATE_ACTIVE;
|
||||
+ atomic_inc(&q->owned_by_drv_count);
|
||||
+
|
||||
+ vbuf = to_vb2_v4l2_buffer(vb);
|
||||
+ vbuf->field = V4L2_FIELD_NONE;
|
||||
+
|
||||
+ v4l2_m2m_last_buffer_done(m2m_ctx, vbuf);
|
||||
+}
|
||||
+
|
||||
int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
@@ -570,11 +668,25 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
__func__);
|
||||
return -EPERM;
|
||||
}
|
||||
+
|
||||
ret = vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf);
|
||||
- if (!ret && !(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * If the capture queue is streaming, but streaming hasn't started
|
||||
+ * on the device, but was asked to stop, mark the previously queued
|
||||
+ * buffer as DONE with LAST flag since it won't be queued on the
|
||||
+ * device.
|
||||
+ */
|
||||
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type) &&
|
||||
+ vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) &&
|
||||
+ (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx)))
|
||||
+ v4l2_m2m_force_last_buf_done(m2m_ctx, vq);
|
||||
+ else if (!(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
|
||||
v4l2_m2m_try_schedule(m2m_ctx);
|
||||
|
||||
- return ret;
|
||||
+ return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
|
||||
|
||||
@@ -1225,6 +1337,62 @@ int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd);
|
||||
|
||||
+int v4l2_m2m_encoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct v4l2_encoder_cmd *ec)
|
||||
+{
|
||||
+ if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (ec->cmd == V4L2_ENC_CMD_STOP)
|
||||
+ return v4l2_mark_last_buf(m2m_ctx);
|
||||
+
|
||||
+ if (m2m_ctx->is_draining)
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ if (m2m_ctx->has_stopped)
|
||||
+ m2m_ctx->has_stopped = false;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_encoder_cmd);
|
||||
+
|
||||
+int v4l2_m2m_decoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct v4l2_decoder_cmd *dc)
|
||||
+{
|
||||
+ if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (dc->cmd == V4L2_DEC_CMD_STOP)
|
||||
+ return v4l2_mark_last_buf(m2m_ctx);
|
||||
+
|
||||
+ if (m2m_ctx->is_draining)
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ if (m2m_ctx->has_stopped)
|
||||
+ m2m_ctx->has_stopped = false;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_decoder_cmd);
|
||||
+
|
||||
+int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv,
|
||||
+ struct v4l2_encoder_cmd *ec)
|
||||
+{
|
||||
+ struct v4l2_fh *fh = file->private_data;
|
||||
+
|
||||
+ return v4l2_m2m_encoder_cmd(file, fh->m2m_ctx, ec);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_encoder_cmd);
|
||||
+
|
||||
+int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv,
|
||||
+ struct v4l2_decoder_cmd *dc)
|
||||
+{
|
||||
+ struct v4l2_fh *fh = file->private_data;
|
||||
+
|
||||
+ return v4l2_m2m_decoder_cmd(file, fh->m2m_ctx, dc);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_decoder_cmd);
|
||||
+
|
||||
int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh,
|
||||
struct v4l2_decoder_cmd *dc)
|
||||
{
|
||||
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
|
||||
index 1d85e24791e4..3476889af46c 100644
|
||||
--- a/include/media/v4l2-mem2mem.h
|
||||
+++ b/include/media/v4l2-mem2mem.h
|
||||
@@ -80,6 +80,10 @@ struct v4l2_m2m_queue_ctx {
|
||||
* for an existing frame. This is always true unless
|
||||
* V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF is set, which
|
||||
* indicates slicing support.
|
||||
+ * @is_draining: indicates device is in draining phase
|
||||
+ * @last_src_buf: indicate the last source buffer for draining
|
||||
+ * @next_buf_last: next capture queud buffer will be tagged as last
|
||||
+ * @has_stopped: indicate the device has been stopped
|
||||
* @m2m_dev: opaque pointer to the internal data to handle M2M context
|
||||
* @cap_q_ctx: Capture (output to memory) queue context
|
||||
* @out_q_ctx: Output (input from memory) queue context
|
||||
@@ -98,6 +102,11 @@ struct v4l2_m2m_ctx {
|
||||
|
||||
bool new_frame;
|
||||
|
||||
+ bool is_draining;
|
||||
+ struct vb2_v4l2_buffer *last_src_buf;
|
||||
+ bool next_buf_last;
|
||||
+ bool has_stopped;
|
||||
+
|
||||
/* internal use only */
|
||||
struct v4l2_m2m_dev *m2m_dev;
|
||||
|
||||
@@ -215,6 +224,50 @@ v4l2_m2m_buf_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state)
|
||||
vb2_buffer_done(&buf->vb2_buf, state);
|
||||
}
|
||||
|
||||
+static inline void
|
||||
+v4l2_m2m_clear_state(struct v4l2_m2m_ctx *m2m_ctx)
|
||||
+{
|
||||
+ m2m_ctx->next_buf_last = false;
|
||||
+ m2m_ctx->is_draining = false;
|
||||
+ m2m_ctx->has_stopped = false;
|
||||
+}
|
||||
+
|
||||
+static inline void
|
||||
+v4l2_m2m_mark_stopped(struct v4l2_m2m_ctx *m2m_ctx)
|
||||
+{
|
||||
+ m2m_ctx->next_buf_last = false;
|
||||
+ m2m_ctx->is_draining = false;
|
||||
+ m2m_ctx->has_stopped = true;
|
||||
+}
|
||||
+
|
||||
+static inline bool
|
||||
+v4l2_m2m_dst_buf_is_last(struct v4l2_m2m_ctx *m2m_ctx)
|
||||
+{
|
||||
+ return m2m_ctx->is_draining && m2m_ctx->next_buf_last;
|
||||
+}
|
||||
+
|
||||
+static inline bool
|
||||
+v4l2_m2m_has_stopped(struct v4l2_m2m_ctx *m2m_ctx)
|
||||
+{
|
||||
+ return m2m_ctx->has_stopped;
|
||||
+}
|
||||
+
|
||||
+static inline bool
|
||||
+v4l2_m2m_is_last_draining_src_buf(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_v4l2_buffer *buf)
|
||||
+{
|
||||
+ return m2m_ctx->is_draining && buf == m2m_ctx->last_src_buf;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * v4l2_m2m_last_buffer_done() - marks the buffer with LAST flag and DONE
|
||||
+ *
|
||||
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
|
||||
+ * @vbuf: pointer to struct &v4l2_buffer
|
||||
+ */
|
||||
+void v4l2_m2m_last_buffer_done(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_v4l2_buffer *vbuf);
|
||||
+
|
||||
/**
|
||||
* v4l2_m2m_reqbufs() - multi-queue-aware REQBUFS multiplexer
|
||||
*
|
||||
@@ -312,6 +365,44 @@ int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
enum v4l2_buf_type type);
|
||||
|
||||
+/**
|
||||
+ * v4l2_m2m_start_streaming() - handle start of streaming of a video queue
|
||||
+ *
|
||||
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
|
||||
+ * @q: queue
|
||||
+ */
|
||||
+void v4l2_m2m_start_streaming(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_queue *q);
|
||||
+
|
||||
+/**
|
||||
+ * v4l2_m2m_stop_streaming() - handle stop of streaming of a video queue
|
||||
+ *
|
||||
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
|
||||
+ * @q: queue
|
||||
+ */
|
||||
+void v4l2_m2m_stop_streaming(struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct vb2_queue *q);
|
||||
+
|
||||
+/**
|
||||
+ * v4l2_m2m_encoder_cmd() - execute an encoder command
|
||||
+ *
|
||||
+ * @file: pointer to struct &file
|
||||
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
|
||||
+ * @ec: pointer to the encoder command
|
||||
+ */
|
||||
+int v4l2_m2m_encoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct v4l2_encoder_cmd *ec);
|
||||
+
|
||||
+/**
|
||||
+ * v4l2_m2m_decoder_cmd() - execute a decoder command
|
||||
+ *
|
||||
+ * @file: pointer to struct &file
|
||||
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
|
||||
+ * @dc: pointer to the decoder command
|
||||
+ */
|
||||
+int v4l2_m2m_decoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
|
||||
+ struct v4l2_decoder_cmd *dc);
|
||||
+
|
||||
/**
|
||||
* v4l2_m2m_poll() - poll replacement, for destination buffers only
|
||||
*
|
||||
@@ -704,6 +795,10 @@ int v4l2_m2m_ioctl_streamon(struct file *file, void *fh,
|
||||
enum v4l2_buf_type type);
|
||||
int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh,
|
||||
enum v4l2_buf_type type);
|
||||
+int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *fh,
|
||||
+ struct v4l2_encoder_cmd *ec);
|
||||
+int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *fh,
|
||||
+ struct v4l2_decoder_cmd *dc);
|
||||
int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh,
|
||||
struct v4l2_encoder_cmd *ec);
|
||||
int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,304 +0,0 @@
|
||||
From c83df769335de59f61295032f4d93ffdd31e33d9 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 6 Dec 2019 16:24:16 +0100
|
||||
Subject: [PATCH 107/146] FROMLIST: media: vicodec: use v4l2-mem2mem draining,
|
||||
stopped and next-buf-is-last states handling
|
||||
|
||||
Use the previously introduced v4l2-mem2mem core APIs to handle the drainig,
|
||||
stopped and next-buf-is-last states.
|
||||
|
||||
With these changes, the v4l2-compliance still passes with the following
|
||||
commands :
|
||||
v4l2-ctl --stream-mmap --stream-out-mmap --stream-to-hdr out.comp --stream-from in.yuv
|
||||
>>>><><><><><><><><><><><><><><><><>< 15.53 fps
|
||||
15.53 fps
|
||||
><><><><><><><><><><><><>< 13.99 fps
|
||||
13.99 fps
|
||||
><><><><><><><><><><><>< 13.52 fps
|
||||
13.52 fps
|
||||
><><><><><><><><><><><><>< 13.41 fps
|
||||
13.41 fps
|
||||
><><><><><><><><><><><><>< 13.21 fps
|
||||
13.21 fps
|
||||
><><><><><><><><><><><>< 13.09 fps
|
||||
13.09 fps
|
||||
><><><><><><><
|
||||
STOP ENCODER
|
||||
<<<
|
||||
EOS EVENT
|
||||
|
||||
v4l2-compliance --stream-from in.yuv -s
|
||||
|
||||
The output is available at [1]
|
||||
|
||||
v4l2-compliance -d1 --stream-from-hdr out.comp -s
|
||||
|
||||
The output is available at [2]
|
||||
|
||||
No functional changes should be noticed.
|
||||
|
||||
[1] https://termbin.com/25nn
|
||||
[2] https://termbin.com/dza4
|
||||
|
||||
Suggested-by: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
Suggested-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/media/platform/vicodec/vicodec-core.c | 162 ++++++------------
|
||||
1 file changed, 52 insertions(+), 110 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c
|
||||
index 82350097503e..425c47216dae 100644
|
||||
--- a/drivers/media/platform/vicodec/vicodec-core.c
|
||||
+++ b/drivers/media/platform/vicodec/vicodec-core.c
|
||||
@@ -117,15 +117,10 @@ struct vicodec_ctx {
|
||||
struct vicodec_dev *dev;
|
||||
bool is_enc;
|
||||
bool is_stateless;
|
||||
- bool is_draining;
|
||||
- bool next_is_last;
|
||||
- bool has_stopped;
|
||||
spinlock_t *lock;
|
||||
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
|
||||
- struct vb2_v4l2_buffer *last_src_buf;
|
||||
-
|
||||
/* Source and destination queue data */
|
||||
struct vicodec_q_data q_data[2];
|
||||
struct v4l2_fwht_state state;
|
||||
@@ -431,11 +426,11 @@ static void device_run(void *priv)
|
||||
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
|
||||
|
||||
spin_lock(ctx->lock);
|
||||
- if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
|
||||
+ if (!ctx->comp_has_next_frame &&
|
||||
+ v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
|
||||
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
||||
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
- ctx->is_draining = false;
|
||||
- ctx->has_stopped = true;
|
||||
+ v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
|
||||
}
|
||||
if (ctx->is_enc || ctx->is_stateless) {
|
||||
src_buf->sequence = q_src->sequence++;
|
||||
@@ -586,8 +581,6 @@ static int job_ready(void *priv)
|
||||
unsigned int max_to_copy;
|
||||
unsigned int comp_frame_size;
|
||||
|
||||
- if (ctx->has_stopped)
|
||||
- return 0;
|
||||
if (ctx->source_changed)
|
||||
return 0;
|
||||
if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
|
||||
@@ -607,7 +600,8 @@ static int job_ready(void *priv)
|
||||
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
||||
state = get_next_header(ctx, &p, p_src + sz - p);
|
||||
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
||||
- if (ctx->is_draining && src_buf == ctx->last_src_buf)
|
||||
+ if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
|
||||
+ src_buf))
|
||||
return 1;
|
||||
job_remove_src_buf(ctx, state);
|
||||
goto restart;
|
||||
@@ -636,7 +630,8 @@ static int job_ready(void *priv)
|
||||
p += copy;
|
||||
ctx->comp_size += copy;
|
||||
if (ctx->comp_size < max_to_copy) {
|
||||
- if (ctx->is_draining && src_buf == ctx->last_src_buf)
|
||||
+ if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
|
||||
+ src_buf))
|
||||
return 1;
|
||||
job_remove_src_buf(ctx, state);
|
||||
goto restart;
|
||||
@@ -1219,41 +1214,6 @@ static int vidioc_s_selection(struct file *file, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int vicodec_mark_last_buf(struct vicodec_ctx *ctx)
|
||||
-{
|
||||
- struct vb2_v4l2_buffer *next_dst_buf;
|
||||
- int ret = 0;
|
||||
-
|
||||
- spin_lock(ctx->lock);
|
||||
- if (ctx->is_draining) {
|
||||
- ret = -EBUSY;
|
||||
- goto unlock;
|
||||
- }
|
||||
- if (ctx->has_stopped)
|
||||
- goto unlock;
|
||||
-
|
||||
- ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
|
||||
- ctx->is_draining = true;
|
||||
- if (ctx->last_src_buf)
|
||||
- goto unlock;
|
||||
-
|
||||
- next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
|
||||
- if (!next_dst_buf) {
|
||||
- ctx->next_is_last = true;
|
||||
- goto unlock;
|
||||
- }
|
||||
-
|
||||
- next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
||||
- vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
|
||||
- ctx->is_draining = false;
|
||||
- ctx->has_stopped = true;
|
||||
- v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
-
|
||||
-unlock:
|
||||
- spin_unlock(ctx->lock);
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
static int vicodec_encoder_cmd(struct file *file, void *fh,
|
||||
struct v4l2_encoder_cmd *ec)
|
||||
{
|
||||
@@ -1268,18 +1228,19 @@ static int vicodec_encoder_cmd(struct file *file, void *fh,
|
||||
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
||||
return 0;
|
||||
|
||||
- if (ec->cmd == V4L2_ENC_CMD_STOP)
|
||||
- return vicodec_mark_last_buf(ctx);
|
||||
- ret = 0;
|
||||
- spin_lock(ctx->lock);
|
||||
- if (ctx->is_draining) {
|
||||
- ret = -EBUSY;
|
||||
- } else if (ctx->has_stopped) {
|
||||
- ctx->has_stopped = false;
|
||||
+ ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (ec->cmd == V4L2_ENC_CMD_STOP &&
|
||||
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
+
|
||||
+ if (ec->cmd == V4L2_ENC_CMD_START &&
|
||||
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
||||
- }
|
||||
- spin_unlock(ctx->lock);
|
||||
- return ret;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int vicodec_decoder_cmd(struct file *file, void *fh,
|
||||
@@ -1296,18 +1257,19 @@ static int vicodec_decoder_cmd(struct file *file, void *fh,
|
||||
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
||||
return 0;
|
||||
|
||||
- if (dc->cmd == V4L2_DEC_CMD_STOP)
|
||||
- return vicodec_mark_last_buf(ctx);
|
||||
- ret = 0;
|
||||
- spin_lock(ctx->lock);
|
||||
- if (ctx->is_draining) {
|
||||
- ret = -EBUSY;
|
||||
- } else if (ctx->has_stopped) {
|
||||
- ctx->has_stopped = false;
|
||||
+ ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (dc->cmd == V4L2_DEC_CMD_STOP &&
|
||||
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
+
|
||||
+ if (dc->cmd == V4L2_DEC_CMD_START &&
|
||||
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
||||
- }
|
||||
- spin_unlock(ctx->lock);
|
||||
- return ret;
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int vicodec_enum_framesizes(struct file *file, void *fh,
|
||||
@@ -1480,23 +1442,21 @@ static void vicodec_buf_queue(struct vb2_buffer *vb)
|
||||
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
|
||||
};
|
||||
|
||||
- if (vb2_is_streaming(vq_cap)) {
|
||||
- if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
|
||||
- ctx->next_is_last) {
|
||||
- unsigned int i;
|
||||
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
|
||||
+ vb2_is_streaming(vb->vb2_queue) &&
|
||||
+ v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
|
||||
+ unsigned int i;
|
||||
|
||||
- for (i = 0; i < vb->num_planes; i++)
|
||||
- vb->planes[i].bytesused = 0;
|
||||
- vbuf->flags = V4L2_BUF_FLAG_LAST;
|
||||
- vbuf->field = V4L2_FIELD_NONE;
|
||||
- vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++;
|
||||
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
|
||||
- ctx->is_draining = false;
|
||||
- ctx->has_stopped = true;
|
||||
- ctx->next_is_last = false;
|
||||
- v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
- return;
|
||||
- }
|
||||
+ for (i = 0; i < vb->num_planes; i++)
|
||||
+ vb->planes[i].bytesused = 0;
|
||||
+
|
||||
+ vbuf->field = V4L2_FIELD_NONE;
|
||||
+ vbuf->sequence =
|
||||
+ get_q_data(ctx, vb->vb2_queue->type)->sequence++;
|
||||
+
|
||||
+ v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
|
||||
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
+ return;
|
||||
}
|
||||
|
||||
/* buf_queue handles only the first source change event */
|
||||
@@ -1609,8 +1569,7 @@ static int vicodec_start_streaming(struct vb2_queue *q,
|
||||
chroma_div = info->width_div * info->height_div;
|
||||
q_data->sequence = 0;
|
||||
|
||||
- if (V4L2_TYPE_IS_OUTPUT(q->type))
|
||||
- ctx->last_src_buf = NULL;
|
||||
+ v4l2_m2m_start_streaming(ctx->fh.m2m_ctx, q);
|
||||
|
||||
state->gop_cnt = 0;
|
||||
|
||||
@@ -1689,29 +1648,12 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
|
||||
|
||||
vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
|
||||
|
||||
- if (V4L2_TYPE_IS_OUTPUT(q->type)) {
|
||||
- if (ctx->is_draining) {
|
||||
- struct vb2_v4l2_buffer *next_dst_buf;
|
||||
-
|
||||
- spin_lock(ctx->lock);
|
||||
- ctx->last_src_buf = NULL;
|
||||
- next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
|
||||
- if (!next_dst_buf) {
|
||||
- ctx->next_is_last = true;
|
||||
- } else {
|
||||
- next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
||||
- vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
|
||||
- ctx->is_draining = false;
|
||||
- ctx->has_stopped = true;
|
||||
- v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
- }
|
||||
- spin_unlock(ctx->lock);
|
||||
- }
|
||||
- } else {
|
||||
- ctx->is_draining = false;
|
||||
- ctx->has_stopped = false;
|
||||
- ctx->next_is_last = false;
|
||||
- }
|
||||
+ v4l2_m2m_stop_streaming(ctx->fh.m2m_ctx, q);
|
||||
+
|
||||
+ if (V4L2_TYPE_IS_OUTPUT(q->type) &&
|
||||
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||
+ v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||
+
|
||||
if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
|
||||
ctx->first_source_change_sent = false;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,742 +0,0 @@
|
||||
From 394dd80b59761cec3cfbc097897c6d55f2ad8662 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Mon, 7 Oct 2019 16:59:08 +0200
|
||||
Subject: [PATCH 108/146] FROMLIST: media: meson: vdec: bring up to compliance
|
||||
|
||||
Add all the necessary bits to pass v4l2-compliance in stateful decoding
|
||||
mode.
|
||||
|
||||
Mostly includes tracking the state of the decoder, allowing the OUTPUT
|
||||
queue to stream while the CAPTURE queue is inactive, handling resolution
|
||||
change events, draining with V4L2_DEC_CMD_STOP, copying more metadata
|
||||
from the src buffers to the dst buffers, etc.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/staging/media/meson/vdec/esparser.c | 58 +++++-------
|
||||
drivers/staging/media/meson/vdec/vdec.c | 90 ++++++++++++-------
|
||||
drivers/staging/media/meson/vdec/vdec.h | 14 ++-
|
||||
.../staging/media/meson/vdec/vdec_helpers.c | 88 +++++++++---------
|
||||
.../staging/media/meson/vdec/vdec_helpers.h | 6 +-
|
||||
.../staging/media/meson/vdec/vdec_platform.c | 10 +++
|
||||
6 files changed, 149 insertions(+), 117 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
|
||||
index 95102a4bdc62..adc5c1e81a4c 100644
|
||||
--- a/drivers/staging/media/meson/vdec/esparser.c
|
||||
+++ b/drivers/staging/media/meson/vdec/esparser.c
|
||||
@@ -79,22 +79,28 @@ static irqreturn_t esparser_isr(int irq, void *dev)
|
||||
* Also append a start code 000001ff at the end to trigger
|
||||
* the ESPARSER interrupt.
|
||||
*/
|
||||
-static u32 esparser_pad_start_code(struct vb2_buffer *vb)
|
||||
+static u32 esparser_pad_start_code(struct amvdec_core *core, struct vb2_buffer *vb)
|
||||
{
|
||||
u32 payload_size = vb2_get_plane_payload(vb, 0);
|
||||
u32 pad_size = 0;
|
||||
- u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size;
|
||||
+ u8 *vaddr = vb2_plane_vaddr(vb, 0);
|
||||
|
||||
if (payload_size < ESPARSER_MIN_PACKET_SIZE) {
|
||||
pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size;
|
||||
- memset(vaddr, 0, pad_size);
|
||||
+ memset(vaddr + payload_size, 0, pad_size);
|
||||
}
|
||||
|
||||
- memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN);
|
||||
- vaddr[pad_size] = 0x00;
|
||||
- vaddr[pad_size + 1] = 0x00;
|
||||
- vaddr[pad_size + 2] = 0x01;
|
||||
- vaddr[pad_size + 3] = 0xff;
|
||||
+ if ((payload_size + pad_size + SEARCH_PATTERN_LEN) >
|
||||
+ vb2_plane_size(vb, 0)) {
|
||||
+ dev_warn(core->dev, "%s: unable to pad start code\n", __func__);
|
||||
+ return pad_size;
|
||||
+ }
|
||||
+
|
||||
+ memset(vaddr + payload_size + pad_size, 0, SEARCH_PATTERN_LEN);
|
||||
+ vaddr[payload_size + pad_size] = 0x00;
|
||||
+ vaddr[payload_size + pad_size + 1] = 0x00;
|
||||
+ vaddr[payload_size + pad_size + 2] = 0x01;
|
||||
+ vaddr[payload_size + pad_size + 3] = 0xff;
|
||||
|
||||
return pad_size;
|
||||
}
|
||||
@@ -180,31 +186,27 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
|
||||
int ret;
|
||||
struct vb2_buffer *vb = &vbuf->vb2_buf;
|
||||
struct amvdec_core *core = sess->core;
|
||||
- struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
|
||||
- u32 num_dst_bufs = 0;
|
||||
u32 payload_size = vb2_get_plane_payload(vb, 0);
|
||||
dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
u32 offset;
|
||||
u32 pad_size;
|
||||
|
||||
- if (codec_ops->num_pending_bufs)
|
||||
- num_dst_bufs = codec_ops->num_pending_bufs(sess);
|
||||
-
|
||||
- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
|
||||
-
|
||||
- if (esparser_vififo_get_free_space(sess) < payload_size ||
|
||||
- atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
|
||||
+ if (esparser_vififo_get_free_space(sess) < payload_size)
|
||||
return -EAGAIN;
|
||||
|
||||
v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
|
||||
|
||||
offset = esparser_get_offset(sess);
|
||||
|
||||
- amvdec_add_ts_reorder(sess, vb->timestamp, offset);
|
||||
- dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n",
|
||||
- vb->timestamp, payload_size, offset);
|
||||
+ amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags);
|
||||
+ dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X flags = %08X\n",
|
||||
+ vb->timestamp, payload_size, offset, vbuf->flags);
|
||||
+
|
||||
+ vbuf->flags = 0;
|
||||
+ vbuf->field = V4L2_FIELD_NONE;
|
||||
+ vbuf->sequence = sess->sequence_out++;
|
||||
|
||||
- pad_size = esparser_pad_start_code(vb);
|
||||
+ pad_size = esparser_pad_start_code(core, vb);
|
||||
ret = esparser_write_data(core, phy, payload_size + pad_size);
|
||||
|
||||
if (ret <= 0) {
|
||||
@@ -216,19 +218,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- /* We need to wait until we parse the first keyframe.
|
||||
- * All buffers prior to the first keyframe must be dropped.
|
||||
- */
|
||||
- if (!sess->keyframe_found)
|
||||
- usleep_range(1000, 2000);
|
||||
-
|
||||
- if (sess->keyframe_found)
|
||||
- atomic_inc(&sess->esparser_queued_bufs);
|
||||
- else
|
||||
- amvdec_remove_ts(sess, vb->timestamp);
|
||||
-
|
||||
- vbuf->flags = 0;
|
||||
- vbuf->field = V4L2_FIELD_NONE;
|
||||
+ atomic_inc(&sess->esparser_queued_bufs);
|
||||
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
|
||||
|
||||
return 0;
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
|
||||
index 5c5dabed2f09..92f0258868b1 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec.c
|
||||
@@ -168,7 +168,10 @@ static void process_num_buffers(struct vb2_queue *q,
|
||||
{
|
||||
const struct amvdec_format *fmt_out = sess->fmt_out;
|
||||
unsigned int buffers_total = q->num_buffers + *num_buffers;
|
||||
+ u32 min_buf_capture = v4l2_ctrl_g_ctrl(sess->ctrl_min_buf_capture);
|
||||
|
||||
+ if (q->num_buffers + *num_buffers < min_buf_capture)
|
||||
+ *num_buffers = min_buf_capture - q->num_buffers;
|
||||
if (is_reqbufs && buffers_total < fmt_out->min_buffers)
|
||||
*num_buffers = fmt_out->min_buffers - q->num_buffers;
|
||||
if (buffers_total > fmt_out->max_buffers)
|
||||
@@ -193,7 +196,8 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
|
||||
if (*num_planes) {
|
||||
switch (q->type) {
|
||||
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
||||
- if (*num_planes != 1 || sizes[0] < output_size)
|
||||
+ if (*num_planes != 1 ||
|
||||
+ sizes[0] < sess->src_buffer_size)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
||||
@@ -224,7 +228,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
|
||||
|
||||
switch (q->type) {
|
||||
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
||||
- sizes[0] = amvdec_get_output_size(sess);
|
||||
+ sizes[0] = sess->src_buffer_size;
|
||||
*num_planes = 1;
|
||||
break;
|
||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
||||
@@ -250,6 +254,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ sess->changed_format = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -261,10 +266,11 @@ static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
|
||||
|
||||
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
|
||||
|
||||
- if (!sess->streamon_out || !sess->streamon_cap)
|
||||
+ if (!sess->streamon_out)
|
||||
return;
|
||||
|
||||
- if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
|
||||
+ if (sess->streamon_cap &&
|
||||
+ vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
|
||||
vdec_codec_needs_recycle(sess))
|
||||
vdec_queue_recycle(sess, vb);
|
||||
|
||||
@@ -289,16 +295,22 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
else
|
||||
sess->streamon_cap = 1;
|
||||
|
||||
- if (!sess->streamon_out || !sess->streamon_cap)
|
||||
+ if (!sess->streamon_out)
|
||||
return 0;
|
||||
|
||||
if (sess->status == STATUS_NEEDS_RESUME &&
|
||||
- q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
+ q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
|
||||
+ sess->changed_format) {
|
||||
codec_ops->resume(sess);
|
||||
sess->status = STATUS_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ if (sess->status == STATUS_RUNNING ||
|
||||
+ sess->status == STATUS_NEEDS_RESUME ||
|
||||
+ sess->status == STATUS_INIT)
|
||||
+ return 0;
|
||||
+
|
||||
sess->vififo_size = SIZE_VIFIFO;
|
||||
sess->vififo_vaddr =
|
||||
dma_alloc_coherent(sess->core->dev, sess->vififo_size,
|
||||
@@ -323,13 +335,14 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
goto vififo_free;
|
||||
|
||||
sess->sequence_cap = 0;
|
||||
+ sess->sequence_out = 0;
|
||||
if (vdec_codec_needs_recycle(sess))
|
||||
sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
|
||||
"vdec_recycle");
|
||||
|
||||
- sess->status = STATUS_RUNNING;
|
||||
+ sess->status = STATUS_INIT;
|
||||
core->cur_sess = sess;
|
||||
-
|
||||
+ schedule_work(&sess->esparser_queue_work);
|
||||
return 0;
|
||||
|
||||
vififo_free:
|
||||
@@ -386,6 +399,7 @@ static void vdec_stop_streaming(struct vb2_queue *q)
|
||||
struct vb2_v4l2_buffer *buf;
|
||||
|
||||
if (sess->status == STATUS_RUNNING ||
|
||||
+ sess->status == STATUS_INIT ||
|
||||
(sess->status == STATUS_NEEDS_RESUME &&
|
||||
(!sess->streamon_out || !sess->streamon_cap))) {
|
||||
if (vdec_codec_needs_recycle(sess))
|
||||
@@ -476,20 +490,34 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
|
||||
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
|
||||
struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
|
||||
const struct amvdec_format *fmts = sess->core->platform->formats;
|
||||
- const struct amvdec_format *fmt_out;
|
||||
+ const struct amvdec_format *fmt_out = NULL;
|
||||
+ u32 output_size = 0;
|
||||
|
||||
memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
|
||||
memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
|
||||
|
||||
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
||||
+ switch (f->type) {
|
||||
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
||||
fmt_out = find_format(fmts, size, pixmp->pixelformat);
|
||||
if (!fmt_out) {
|
||||
pixmp->pixelformat = V4L2_PIX_FMT_MPEG2;
|
||||
fmt_out = find_format(fmts, size, pixmp->pixelformat);
|
||||
}
|
||||
+ break;
|
||||
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
||||
+ fmt_out = sess->fmt_out;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
- pfmt[0].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height);
|
||||
+ pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width);
|
||||
+ pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
|
||||
+ output_size = get_output_size(pixmp->width, pixmp->height);
|
||||
+
|
||||
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
||||
+ if (!pfmt[0].sizeimage)
|
||||
+ pfmt[0].sizeimage = sess->src_buffer_size;
|
||||
pfmt[0].bytesperline = 0;
|
||||
pixmp->num_planes = 1;
|
||||
} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
@@ -499,35 +527,25 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
|
||||
|
||||
memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
|
||||
if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) {
|
||||
- pfmt[0].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height);
|
||||
+ pfmt[0].sizeimage = output_size;
|
||||
pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
|
||||
|
||||
- pfmt[1].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height) / 2;
|
||||
+ pfmt[1].sizeimage = output_size / 2;
|
||||
pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
|
||||
pixmp->num_planes = 2;
|
||||
} else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) {
|
||||
- pfmt[0].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height);
|
||||
+ pfmt[0].sizeimage = output_size;
|
||||
pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
|
||||
|
||||
- pfmt[1].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height) / 4;
|
||||
+ pfmt[1].sizeimage = output_size / 4;
|
||||
pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2;
|
||||
|
||||
- pfmt[2].sizeimage =
|
||||
- get_output_size(pixmp->width, pixmp->height) / 4;
|
||||
+ pfmt[2].sizeimage = output_size / 2;
|
||||
pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
|
||||
pixmp->num_planes = 3;
|
||||
}
|
||||
- } else {
|
||||
- return NULL;
|
||||
}
|
||||
|
||||
- pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width);
|
||||
- pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
|
||||
-
|
||||
if (pixmp->field == V4L2_FIELD_ANY)
|
||||
pixmp->field = V4L2_FIELD_NONE;
|
||||
|
||||
@@ -586,6 +604,8 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
|
||||
orig_pixmp = *pixmp;
|
||||
|
||||
fmt_out = vdec_try_fmt_common(sess, num_formats, f);
|
||||
+ if (!fmt_out)
|
||||
+ return -EINVAL;
|
||||
|
||||
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
||||
pixfmt_out = pixmp->pixelformat;
|
||||
@@ -610,6 +630,7 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
|
||||
sess->ycbcr_enc = pixmp->ycbcr_enc;
|
||||
sess->quantization = pixmp->quantization;
|
||||
sess->xfer_func = pixmp->xfer_func;
|
||||
+ sess->src_buffer_size = pixmp->plane_fmt[0].sizeimage;
|
||||
}
|
||||
|
||||
memset(&format, 0, sizeof(format));
|
||||
@@ -701,29 +722,31 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
|
||||
if (!(sess->streamon_out & sess->streamon_cap))
|
||||
return 0;
|
||||
|
||||
- /* Currently not handled since we do not support dynamic resolution
|
||||
- * for MPEG2. We consider both queues streaming to mean that the
|
||||
- * decoding session is started
|
||||
- */
|
||||
- if (cmd->cmd == V4L2_DEC_CMD_START)
|
||||
+ if (cmd->cmd == V4L2_DEC_CMD_START) {
|
||||
+ v4l2_m2m_clear_state(sess->m2m_ctx);
|
||||
+ sess->should_stop = 0;
|
||||
return 0;
|
||||
+ }
|
||||
|
||||
/* Should not happen */
|
||||
if (cmd->cmd != V4L2_DEC_CMD_STOP)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
|
||||
+
|
||||
sess->should_stop = 1;
|
||||
|
||||
- vdec_wait_inactive(sess);
|
||||
+ v4l2_m2m_mark_stopped(sess->m2m_ctx);
|
||||
|
||||
if (codec_ops->drain) {
|
||||
+ vdec_wait_inactive(sess);
|
||||
codec_ops->drain(sess);
|
||||
} else if (codec_ops->eos_sequence) {
|
||||
u32 len;
|
||||
const u8 *data = codec_ops->eos_sequence(&len);
|
||||
|
||||
esparser_queue_eos(sess->core, data, len);
|
||||
+ vdec_wait_inactive(sess);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -883,6 +906,7 @@ static int vdec_open(struct file *file)
|
||||
sess->height = 720;
|
||||
sess->pixelaspect.numerator = 1;
|
||||
sess->pixelaspect.denominator = 1;
|
||||
+ sess->src_buffer_size = SZ_1M;
|
||||
|
||||
INIT_LIST_HEAD(&sess->timestamps);
|
||||
INIT_LIST_HEAD(&sess->bufs_recycle);
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
|
||||
index 0faa1ec4858e..f95445ac0658 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec.h
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec.h
|
||||
@@ -29,13 +29,19 @@ struct amvdec_buffer {
|
||||
* struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
|
||||
*
|
||||
* @list: used to make lists out of this struct
|
||||
- * @ts: timestamp
|
||||
+ * @tc: timecode from the v4l2 buffer
|
||||
+ * @ts: timestamp from the VB2 buffer
|
||||
* @offset: offset in the VIFIFO where the associated packet was written
|
||||
+ * @flags: flags from the v4l2 buffer
|
||||
+ * @used_count: times this timestamp was checked for a match with a dst buffer
|
||||
*/
|
||||
struct amvdec_timestamp {
|
||||
struct list_head list;
|
||||
+ struct v4l2_timecode tc;
|
||||
u64 ts;
|
||||
u32 offset;
|
||||
+ u32 flags;
|
||||
+ u32 used_count;
|
||||
};
|
||||
|
||||
struct amvdec_session;
|
||||
@@ -165,6 +171,7 @@ struct amvdec_format {
|
||||
|
||||
enum amvdec_status {
|
||||
STATUS_STOPPED,
|
||||
+ STATUS_INIT,
|
||||
STATUS_RUNNING,
|
||||
STATUS_NEEDS_RESUME,
|
||||
};
|
||||
@@ -180,6 +187,7 @@ enum amvdec_status {
|
||||
* @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
|
||||
* @fmt_out: vdec pixel format for the OUTPUT queue
|
||||
* @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
|
||||
+ * @src_buffer_size: size in bytes of the OUTPUT buffers' only plane
|
||||
* @width: current picture width
|
||||
* @height: current picture height
|
||||
* @colorspace: current colorspace
|
||||
@@ -221,6 +229,7 @@ struct amvdec_session {
|
||||
|
||||
const struct amvdec_format *fmt_out;
|
||||
u32 pixfmt_cap;
|
||||
+ u32 src_buffer_size;
|
||||
|
||||
u32 width;
|
||||
u32 height;
|
||||
@@ -235,10 +244,11 @@ struct amvdec_session {
|
||||
struct work_struct esparser_queue_work;
|
||||
|
||||
unsigned int streamon_cap, streamon_out;
|
||||
- unsigned int sequence_cap;
|
||||
+ unsigned int sequence_cap, sequence_out;
|
||||
unsigned int should_stop;
|
||||
unsigned int keyframe_found;
|
||||
unsigned int num_dst_bufs;
|
||||
+ unsigned int changed_format;
|
||||
|
||||
u8 canvas_alloc[MAX_CANVAS];
|
||||
u32 canvas_num;
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
index f16948bdbf2f..a4970ec1bf2e 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
@@ -200,33 +200,23 @@ int amvdec_set_canvases(struct amvdec_session *sess,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amvdec_set_canvases);
|
||||
|
||||
-void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
|
||||
+void amvdec_add_ts(struct amvdec_session *sess, u64 ts,
|
||||
+ struct v4l2_timecode tc, u32 offset, u32 vbuf_flags)
|
||||
{
|
||||
- struct amvdec_timestamp *new_ts, *tmp;
|
||||
+ struct amvdec_timestamp *new_ts;
|
||||
unsigned long flags;
|
||||
|
||||
- new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
|
||||
+ new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL);
|
||||
new_ts->ts = ts;
|
||||
+ new_ts->tc = tc;
|
||||
new_ts->offset = offset;
|
||||
+ new_ts->flags = vbuf_flags;
|
||||
|
||||
spin_lock_irqsave(&sess->ts_spinlock, flags);
|
||||
-
|
||||
- if (list_empty(&sess->timestamps))
|
||||
- goto add_tail;
|
||||
-
|
||||
- list_for_each_entry(tmp, &sess->timestamps, list) {
|
||||
- if (ts <= tmp->ts) {
|
||||
- list_add_tail(&new_ts->list, &tmp->list);
|
||||
- goto unlock;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
-add_tail:
|
||||
list_add_tail(&new_ts->list, &sess->timestamps);
|
||||
-unlock:
|
||||
spin_unlock_irqrestore(&sess->ts_spinlock, flags);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
|
||||
+EXPORT_SYMBOL_GPL(amvdec_add_ts);
|
||||
|
||||
void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
|
||||
{
|
||||
@@ -251,8 +241,8 @@ EXPORT_SYMBOL_GPL(amvdec_remove_ts);
|
||||
|
||||
static void dst_buf_done(struct amvdec_session *sess,
|
||||
struct vb2_v4l2_buffer *vbuf,
|
||||
- u32 field,
|
||||
- u64 timestamp)
|
||||
+ u32 field, u64 timestamp,
|
||||
+ struct v4l2_timecode timecode, u32 flags)
|
||||
{
|
||||
struct device *dev = sess->core->dev_dec;
|
||||
u32 output_size = amvdec_get_output_size(sess);
|
||||
@@ -271,19 +261,23 @@ static void dst_buf_done(struct amvdec_session *sess,
|
||||
|
||||
vbuf->vb2_buf.timestamp = timestamp;
|
||||
vbuf->sequence = sess->sequence_cap++;
|
||||
+ vbuf->flags = flags;
|
||||
+ vbuf->timecode = timecode;
|
||||
|
||||
if (sess->should_stop &&
|
||||
- atomic_read(&sess->esparser_queued_bufs) <= 2) {
|
||||
+ atomic_read(&sess->esparser_queued_bufs) <= 1) {
|
||||
const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
|
||||
|
||||
- dev_dbg(dev, "Signaling EOS\n");
|
||||
+ dev_dbg(dev, "Signaling EOS, sequence_cap = %u\n",
|
||||
+ sess->sequence_cap - 1);
|
||||
v4l2_event_queue_fh(&sess->fh, &ev);
|
||||
vbuf->flags |= V4L2_BUF_FLAG_LAST;
|
||||
} else if (sess->should_stop)
|
||||
dev_dbg(dev, "should_stop, %u bufs remain\n",
|
||||
atomic_read(&sess->esparser_queued_bufs));
|
||||
|
||||
- dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
|
||||
+ dev_dbg(dev, "Buffer %u done, ts = %llu, flags = %08X\n",
|
||||
+ vbuf->vb2_buf.index, timestamp, flags);
|
||||
vbuf->field = field;
|
||||
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
|
||||
|
||||
@@ -297,7 +291,9 @@ void amvdec_dst_buf_done(struct amvdec_session *sess,
|
||||
struct device *dev = sess->core->dev_dec;
|
||||
struct amvdec_timestamp *tmp;
|
||||
struct list_head *timestamps = &sess->timestamps;
|
||||
+ struct v4l2_timecode timecode;
|
||||
u64 timestamp;
|
||||
+ u32 vbuf_flags;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sess->ts_spinlock, flags);
|
||||
@@ -312,11 +308,13 @@ void amvdec_dst_buf_done(struct amvdec_session *sess,
|
||||
|
||||
tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
|
||||
timestamp = tmp->ts;
|
||||
+ timecode = tmp->tc;
|
||||
+ vbuf_flags = tmp->flags;
|
||||
list_del(&tmp->list);
|
||||
kfree(tmp);
|
||||
spin_unlock_irqrestore(&sess->ts_spinlock, flags);
|
||||
|
||||
- dst_buf_done(sess, vbuf, field, timestamp);
|
||||
+ dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
|
||||
atomic_dec(&sess->esparser_queued_bufs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
|
||||
@@ -328,48 +326,43 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
|
||||
struct device *dev = sess->core->dev_dec;
|
||||
struct amvdec_timestamp *match = NULL;
|
||||
struct amvdec_timestamp *tmp, *n;
|
||||
+ struct v4l2_timecode timecode = { 0 };
|
||||
u64 timestamp = 0;
|
||||
+ u32 vbuf_flags = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sess->ts_spinlock, flags);
|
||||
|
||||
/* Look for our vififo offset to get the corresponding timestamp. */
|
||||
list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
|
||||
- s64 delta = (s64)offset - tmp->offset;
|
||||
-
|
||||
- /* Offsets reported by codecs usually differ slightly,
|
||||
- * so we need some wiggle room.
|
||||
- * 4KiB being the minimum packet size, there is no risk here.
|
||||
- */
|
||||
- if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
|
||||
- match = tmp;
|
||||
+ if (tmp->offset > offset) {
|
||||
+ /*
|
||||
+ * Delete any record that remained unused for 32 match
|
||||
+ * checks
|
||||
+ */
|
||||
+ if (tmp->used_count++ >= 32) {
|
||||
+ list_del(&tmp->list);
|
||||
+ kfree(tmp);
|
||||
+ }
|
||||
break;
|
||||
}
|
||||
|
||||
- if (!allow_drop)
|
||||
- continue;
|
||||
-
|
||||
- /* Delete any timestamp entry that appears before our target
|
||||
- * (not all src packets/timestamps lead to a frame)
|
||||
- */
|
||||
- if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
|
||||
- atomic_dec(&sess->esparser_queued_bufs);
|
||||
- list_del(&tmp->list);
|
||||
- kfree(tmp);
|
||||
- }
|
||||
+ match = tmp;
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
- dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
|
||||
+ dev_err(dev, "Buffer %u done but can't match offset (%08X)\n",
|
||||
vbuf->vb2_buf.index, offset);
|
||||
} else {
|
||||
timestamp = match->ts;
|
||||
+ timecode = match->tc;
|
||||
+ vbuf_flags = match->flags;
|
||||
list_del(&match->list);
|
||||
kfree(match);
|
||||
}
|
||||
spin_unlock_irqrestore(&sess->ts_spinlock, flags);
|
||||
|
||||
- dst_buf_done(sess, vbuf, field, timestamp);
|
||||
+ dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
|
||||
if (match)
|
||||
atomic_dec(&sess->esparser_queued_bufs);
|
||||
}
|
||||
@@ -420,16 +413,19 @@ void amvdec_src_change(struct amvdec_session *sess, u32 width,
|
||||
|
||||
v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
|
||||
|
||||
- /* Check if the capture queue is already configured well for our
|
||||
+ /*
|
||||
+ * Check if the capture queue is already configured well for our
|
||||
* usecase. If so, keep decoding with it and do not send the event
|
||||
*/
|
||||
- if (sess->width == width &&
|
||||
+ if (sess->streamon_cap &&
|
||||
+ sess->width == width &&
|
||||
sess->height == height &&
|
||||
dpb_size <= sess->num_dst_bufs) {
|
||||
sess->fmt_out->codec_ops->resume(sess);
|
||||
return;
|
||||
}
|
||||
|
||||
+ sess->changed_format = 0;
|
||||
sess->width = width;
|
||||
sess->height = height;
|
||||
sess->status = STATUS_NEEDS_RESUME;
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
index a455a9ee1cc2..165e6293ffba 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
@@ -44,13 +44,15 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
|
||||
u32 offset, u32 field, bool allow_drop);
|
||||
|
||||
/**
|
||||
- * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order
|
||||
+ * amvdec_add_ts() - Add a timestamp to the list
|
||||
*
|
||||
* @sess: current session
|
||||
* @ts: timestamp to add
|
||||
* @offset: offset in the VIFIFO where the associated packet was written
|
||||
+ * @flags the vb2_v4l2_buffer flags
|
||||
*/
|
||||
-void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset);
|
||||
+void amvdec_add_ts(struct amvdec_session *sess, u64 ts,
|
||||
+ struct v4l2_timecode tc, u32 offset, u32 flags);
|
||||
void amvdec_remove_ts(struct amvdec_session *sess, u64 ts);
|
||||
|
||||
/**
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
index ea39f8209ec7..066d4a055894 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
@@ -21,6 +21,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
}, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG2,
|
||||
.min_buffers = 8,
|
||||
@@ -31,6 +32,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -45,6 +47,7 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
}, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG2,
|
||||
.min_buffers = 8,
|
||||
@@ -55,6 +58,7 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -69,6 +73,7 @@ static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
}, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG2,
|
||||
.min_buffers = 8,
|
||||
@@ -79,6 +84,7 @@ static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -93,6 +99,7 @@ static const struct amvdec_format vdec_formats_g12a[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
}, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG2,
|
||||
.min_buffers = 8,
|
||||
@@ -103,6 +110,7 @@ static const struct amvdec_format vdec_formats_g12a[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -117,6 +125,7 @@ static const struct amvdec_format vdec_formats_sm1[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
}, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG2,
|
||||
.min_buffers = 8,
|
||||
@@ -127,6 +136,7 @@ static const struct amvdec_format vdec_formats_sm1[] = {
|
||||
.codec_ops = &codec_mpeg12_ops,
|
||||
.firmware_path = "meson/vdec/gxl_mpeg12.bin",
|
||||
.pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
|
||||
},
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,645 +0,0 @@
|
||||
From 7a3c513748adda914edc321d0f5d2b0d54d0aa04 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Mon, 7 Oct 2019 16:59:09 +0200
|
||||
Subject: [PATCH 109/146] FROMLIST: media: meson: vdec: add H.264 decoding
|
||||
support
|
||||
|
||||
Add support for the H264 compressed format (V4L2_PIX_FMT_H264).
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/staging/media/meson/vdec/Makefile | 2 +-
|
||||
drivers/staging/media/meson/vdec/codec_h264.c | 482 ++++++++++++++++++
|
||||
drivers/staging/media/meson/vdec/codec_h264.h | 14 +
|
||||
.../staging/media/meson/vdec/vdec_platform.c | 61 +++
|
||||
4 files changed, 558 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/staging/media/meson/vdec/codec_h264.c
|
||||
create mode 100644 drivers/staging/media/meson/vdec/codec_h264.h
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile
|
||||
index 6bea129084b7..711d990c760e 100644
|
||||
--- a/drivers/staging/media/meson/vdec/Makefile
|
||||
+++ b/drivers/staging/media/meson/vdec/Makefile
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
|
||||
meson-vdec-objs += vdec_1.o
|
||||
-meson-vdec-objs += codec_mpeg12.o
|
||||
+meson-vdec-objs += codec_mpeg12.o codec_h264.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
|
||||
diff --git a/drivers/staging/media/meson/vdec/codec_h264.c b/drivers/staging/media/meson/vdec/codec_h264.c
|
||||
new file mode 100644
|
||||
index 000000000000..4528a6a01c3d
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/codec_h264.c
|
||||
@@ -0,0 +1,482 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2019 BayLibre, SAS
|
||||
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#include <media/v4l2-mem2mem.h>
|
||||
+#include <media/videobuf2-dma-contig.h>
|
||||
+
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "dos_regs.h"
|
||||
+
|
||||
+#define SIZE_EXT_FW (20 * SZ_1K)
|
||||
+#define SIZE_WORKSPACE 0x1ee000
|
||||
+#define SIZE_SEI (8 * SZ_1K)
|
||||
+
|
||||
+/*
|
||||
+ * Offset added by the firmware which must be substracted
|
||||
+ * from the workspace phyaddr
|
||||
+ */
|
||||
+#define WORKSPACE_BUF_OFFSET 0x1000000
|
||||
+
|
||||
+/* ISR status */
|
||||
+#define CMD_MASK GENMASK(7, 0)
|
||||
+#define CMD_SRC_CHANGE 1
|
||||
+#define CMD_FRAMES_READY 2
|
||||
+#define CMD_FATAL_ERROR 6
|
||||
+#define CMD_BAD_WIDTH 7
|
||||
+#define CMD_BAD_HEIGHT 8
|
||||
+
|
||||
+#define SEI_DATA_READY BIT(15)
|
||||
+
|
||||
+/* Picture type */
|
||||
+#define PIC_TOP_BOT 5
|
||||
+#define PIC_BOT_TOP 6
|
||||
+
|
||||
+/* Size of Motion Vector per macroblock */
|
||||
+#define MB_MV_SIZE 96
|
||||
+
|
||||
+/* Frame status data */
|
||||
+#define PIC_STRUCT_BIT 5
|
||||
+#define PIC_STRUCT_MASK GENMASK(2, 0)
|
||||
+#define BUF_IDX_MASK GENMASK(4, 0)
|
||||
+#define ERROR_FLAG BIT(9)
|
||||
+#define OFFSET_BIT 16
|
||||
+#define OFFSET_MASK GENMASK(15, 0)
|
||||
+
|
||||
+/* Bitstream parsed data */
|
||||
+#define MB_TOTAL_BIT 8
|
||||
+#define MB_TOTAL_MASK GENMASK(15, 0)
|
||||
+#define MB_WIDTH_MASK GENMASK(7, 0)
|
||||
+#define MAX_REF_BIT 24
|
||||
+#define MAX_REF_MASK GENMASK(6, 0)
|
||||
+#define AR_IDC_BIT 16
|
||||
+#define AR_IDC_MASK GENMASK(7, 0)
|
||||
+#define AR_PRESENT_FLAG BIT(0)
|
||||
+#define AR_EXTEND 0xff
|
||||
+
|
||||
+/*
|
||||
+ * Buffer to send to the ESPARSER to signal End Of Stream for H.264.
|
||||
+ * This is a 16x16 encoded picture that will trigger drain firmware-side.
|
||||
+ * There is no known alternative.
|
||||
+ */
|
||||
+static const u8 eos_sequence[SZ_4K] = {
|
||||
+ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd,
|
||||
+ 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef,
|
||||
+ 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20,
|
||||
+ 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37,
|
||||
+ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34,
|
||||
+ 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20,
|
||||
+ 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79,
|
||||
+ 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30,
|
||||
+ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
|
||||
+ 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e,
|
||||
+ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74,
|
||||
+ 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
+ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65,
|
||||
+ 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d,
|
||||
+ 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73,
|
||||
+ 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20,
|
||||
+ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65,
|
||||
+ 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e,
|
||||
+ 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f,
|
||||
+ 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e,
|
||||
+ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61,
|
||||
+ 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
|
||||
+ 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30,
|
||||
+ 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a,
|
||||
+ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68,
|
||||
+ 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73,
|
||||
+ 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,
|
||||
+ 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63,
|
||||
+ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66,
|
||||
+ 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d,
|
||||
+ 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
|
||||
+ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d,
|
||||
+ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d,
|
||||
+ 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69,
|
||||
+ 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74,
|
||||
+ 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f,
|
||||
+ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69,
|
||||
+ 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35,
|
||||
+ 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69,
|
||||
+ 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
|
||||
+ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
|
||||
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20,
|
||||
+ 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4,
|
||||
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01,
|
||||
+ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6,
|
||||
+ 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4,
|
||||
+ 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7,
|
||||
+ 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09,
|
||||
+ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66,
|
||||
+ 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b,
|
||||
+ 0x00, 0x00, 0x01, 0x0ff,
|
||||
+};
|
||||
+
|
||||
+static const u8 *codec_h264_eos_sequence(u32 *len)
|
||||
+{
|
||||
+ *len = ARRAY_SIZE(eos_sequence);
|
||||
+ return eos_sequence;
|
||||
+}
|
||||
+
|
||||
+struct codec_h264 {
|
||||
+ /* H.264 decoder requires an extended firmware */
|
||||
+ void *ext_fw_vaddr;
|
||||
+ dma_addr_t ext_fw_paddr;
|
||||
+
|
||||
+ /* Buffer for the H.264 Workspace */
|
||||
+ void *workspace_vaddr;
|
||||
+ dma_addr_t workspace_paddr;
|
||||
+
|
||||
+ /* Buffer for the H.264 references MV */
|
||||
+ void *ref_vaddr;
|
||||
+ dma_addr_t ref_paddr;
|
||||
+ u32 ref_size;
|
||||
+
|
||||
+ /* Buffer for parsed SEI data */
|
||||
+ void *sei_vaddr;
|
||||
+ dma_addr_t sei_paddr;
|
||||
+
|
||||
+ u32 mb_width;
|
||||
+ u32 mb_height;
|
||||
+ u32 max_refs;
|
||||
+};
|
||||
+
|
||||
+static int codec_h264_can_recycle(struct amvdec_core *core)
|
||||
+{
|
||||
+ return !amvdec_read_dos(core, AV_SCRATCH_7) ||
|
||||
+ !amvdec_read_dos(core, AV_SCRATCH_8);
|
||||
+}
|
||||
+
|
||||
+static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx)
|
||||
+{
|
||||
+ /*
|
||||
+ * Tell the firmware it can recycle this buffer.
|
||||
+ * AV_SCRATCH_8 serves the same purpose.
|
||||
+ */
|
||||
+ if (!amvdec_read_dos(core, AV_SCRATCH_7))
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1);
|
||||
+ else
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1);
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_start(struct amvdec_session *sess)
|
||||
+{
|
||||
+ u32 workspace_offset;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+
|
||||
+ /* Allocate some memory for the H.264 decoder's state */
|
||||
+ h264->workspace_vaddr =
|
||||
+ dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ &h264->workspace_paddr, GFP_KERNEL);
|
||||
+ if (!h264->workspace_vaddr)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ /* Allocate some memory for the H.264 SEI dump */
|
||||
+ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI,
|
||||
+ &h264->sei_paddr, GFP_KERNEL);
|
||||
+ if (!h264->sei_vaddr)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6));
|
||||
+
|
||||
+ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET;
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr -
|
||||
+ workspace_offset);
|
||||
+
|
||||
+ /* Enable "error correction" */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_F,
|
||||
+ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) |
|
||||
+ BIT(4) | BIT(7));
|
||||
+
|
||||
+ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_stop(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ if (h264->ext_fw_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_EXT_FW,
|
||||
+ h264->ext_fw_vaddr, h264->ext_fw_paddr);
|
||||
+
|
||||
+ if (h264->workspace_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ h264->workspace_vaddr, h264->workspace_paddr);
|
||||
+
|
||||
+ if (h264->ref_vaddr)
|
||||
+ dma_free_coherent(core->dev, h264->ref_size,
|
||||
+ h264->ref_vaddr, h264->ref_paddr);
|
||||
+
|
||||
+ if (h264->sei_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_SEI,
|
||||
+ h264->sei_vaddr, h264->sei_paddr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_load_extended_firmware(struct amvdec_session *sess,
|
||||
+ const u8 *data, u32 len)
|
||||
+{
|
||||
+ struct codec_h264 *h264;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ if (len < SIZE_EXT_FW)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
|
||||
+ if (!h264)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
|
||||
+ &h264->ext_fw_paddr, GFP_KERNEL);
|
||||
+ if (!h264->ext_fw_vaddr) {
|
||||
+ kfree(h264);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
|
||||
+ sess->priv = h264;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct v4l2_fract par_table[] = {
|
||||
+ { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 },
|
||||
+ { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 },
|
||||
+ { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 },
|
||||
+ { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 },
|
||||
+ { 2, 1 }
|
||||
+};
|
||||
+
|
||||
+static void codec_h264_set_par(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2);
|
||||
+ u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK;
|
||||
+
|
||||
+ if (!(seq_info & AR_PRESENT_FLAG))
|
||||
+ return;
|
||||
+
|
||||
+ if (ar_idc == AR_EXTEND) {
|
||||
+ u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3);
|
||||
+
|
||||
+ sess->pixelaspect.numerator = ar_info & 0xffff;
|
||||
+ sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (ar_idc >= ARRAY_SIZE(par_table))
|
||||
+ return;
|
||||
+
|
||||
+ sess->pixelaspect = par_table[ar_idc];
|
||||
+}
|
||||
+
|
||||
+static void codec_h264_resume(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ u32 mb_width, mb_height, mb_total;
|
||||
+
|
||||
+ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 },
|
||||
+ (u32[]){ 24, 0 });
|
||||
+
|
||||
+ dev_dbg(core->dev, "max_refs = %u; actual_dpb_size = %u\n",
|
||||
+ h264->max_refs, sess->num_dst_bufs);
|
||||
+
|
||||
+ /* Align to a multiple of 4 macroblocks */
|
||||
+ mb_width = ALIGN(h264->mb_width, 4);
|
||||
+ mb_height = ALIGN(h264->mb_height, 4);
|
||||
+ mb_total = mb_width * mb_height;
|
||||
+
|
||||
+ h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs;
|
||||
+ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size,
|
||||
+ &h264->ref_paddr, GFP_KERNEL);
|
||||
+ if (!h264->ref_vaddr) {
|
||||
+ amvdec_abort(sess);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Address to store the references' MVs */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr);
|
||||
+ /* End of ref MV */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size);
|
||||
+
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) |
|
||||
+ (sess->num_dst_bufs << 16) |
|
||||
+ ((h264->max_refs - 1) << 8));
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Configure the H.264 decoder when the parser detected a parameter set change
|
||||
+ */
|
||||
+static void codec_h264_src_change(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ u32 parsed_info, mb_total;
|
||||
+ u32 crop_infor, crop_bottom, crop_right;
|
||||
+ u32 frame_width, frame_height;
|
||||
+
|
||||
+ sess->keyframe_found = 1;
|
||||
+
|
||||
+ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1);
|
||||
+
|
||||
+ /* Total number of 16x16 macroblocks */
|
||||
+ mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK;
|
||||
+ /* Number of macroblocks per line */
|
||||
+ h264->mb_width = parsed_info & MB_WIDTH_MASK;
|
||||
+ /* Number of macroblock lines */
|
||||
+ h264->mb_height = mb_total / h264->mb_width;
|
||||
+
|
||||
+ h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1;
|
||||
+
|
||||
+ crop_infor = amvdec_read_dos(core, AV_SCRATCH_6);
|
||||
+ crop_bottom = (crop_infor & 0xff);
|
||||
+ crop_right = (crop_infor >> 16) & 0xff;
|
||||
+
|
||||
+ frame_width = h264->mb_width * 16 - crop_right;
|
||||
+ frame_height = h264->mb_height * 16 - crop_bottom;
|
||||
+
|
||||
+ dev_dbg(core->dev, "frame: %ux%u; crop: %u %u\n",
|
||||
+ frame_width, frame_height, crop_right, crop_bottom);
|
||||
+
|
||||
+ codec_h264_set_par(sess);
|
||||
+ amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * The bitstream offset is split in half in 2 different registers.
|
||||
+ * Fetch its MSB here, which location depends on the frame number.
|
||||
+ */
|
||||
+static u32 get_offset_msb(struct amvdec_core *core, int frame_num)
|
||||
+{
|
||||
+ int take_msb = frame_num % 2;
|
||||
+ int reg_offset = (frame_num / 2) * 4;
|
||||
+ u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset);
|
||||
+
|
||||
+ if (take_msb)
|
||||
+ return offset_msb & 0xffff0000;
|
||||
+
|
||||
+ return (offset_msb & 0x0000ffff) << 16;
|
||||
+}
|
||||
+
|
||||
+static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ int error_count;
|
||||
+ int num_frames;
|
||||
+ int i;
|
||||
+
|
||||
+ error_count = amvdec_read_dos(core, AV_SCRATCH_D);
|
||||
+ num_frames = (status >> 8) & 0xff;
|
||||
+ if (error_count) {
|
||||
+ dev_warn(core->dev,
|
||||
+ "decoder error(s) happened, count %d\n", error_count);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_D, 0);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num_frames; i++) {
|
||||
+ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4);
|
||||
+ u32 buffer_index = frame_status & BUF_IDX_MASK;
|
||||
+ u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) &
|
||||
+ PIC_STRUCT_MASK;
|
||||
+ u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK;
|
||||
+ u32 field = V4L2_FIELD_NONE;
|
||||
+
|
||||
+ /*
|
||||
+ * A buffer decode error means it was decoded,
|
||||
+ * but part of the picture will have artifacts.
|
||||
+ * Typical reason is a temporarily corrupted bitstream
|
||||
+ */
|
||||
+ if (frame_status & ERROR_FLAG)
|
||||
+ dev_dbg(core->dev, "Buffer %d decode error\n",
|
||||
+ buffer_index);
|
||||
+
|
||||
+ if (pic_struct == PIC_TOP_BOT)
|
||||
+ field = V4L2_FIELD_INTERLACED_TB;
|
||||
+ else if (pic_struct == PIC_BOT_TOP)
|
||||
+ field = V4L2_FIELD_INTERLACED_BT;
|
||||
+
|
||||
+ offset |= get_offset_msb(core, i);
|
||||
+ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ u32 status;
|
||||
+ u32 size;
|
||||
+ u8 cmd;
|
||||
+
|
||||
+ status = amvdec_read_dos(core, AV_SCRATCH_0);
|
||||
+ cmd = status & CMD_MASK;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case CMD_SRC_CHANGE:
|
||||
+ codec_h264_src_change(sess);
|
||||
+ break;
|
||||
+ case CMD_FRAMES_READY:
|
||||
+ codec_h264_frames_ready(sess, status);
|
||||
+ break;
|
||||
+ case CMD_FATAL_ERROR:
|
||||
+ dev_err(core->dev, "H.264 decoder fatal error\n");
|
||||
+ goto abort;
|
||||
+ case CMD_BAD_WIDTH:
|
||||
+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
|
||||
+ dev_err(core->dev, "Unsupported video width: %u\n", size);
|
||||
+ goto abort;
|
||||
+ case CMD_BAD_HEIGHT:
|
||||
+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
|
||||
+ dev_err(core->dev, "Unsupported video height: %u\n", size);
|
||||
+ goto abort;
|
||||
+ case 0: /* Unused but not worth printing for */
|
||||
+ case 9:
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (cmd && cmd != CMD_SRC_CHANGE)
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, 0);
|
||||
+
|
||||
+ /* Decoder has some SEI data for us ; ignore */
|
||||
+ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY)
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_J, 0);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+abort:
|
||||
+ amvdec_abort(sess);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_h264_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
+
|
||||
+ return IRQ_WAKE_THREAD;
|
||||
+}
|
||||
+
|
||||
+struct amvdec_codec_ops codec_h264_ops = {
|
||||
+ .start = codec_h264_start,
|
||||
+ .stop = codec_h264_stop,
|
||||
+ .load_extended_firmware = codec_h264_load_extended_firmware,
|
||||
+ .isr = codec_h264_isr,
|
||||
+ .threaded_isr = codec_h264_threaded_isr,
|
||||
+ .can_recycle = codec_h264_can_recycle,
|
||||
+ .recycle = codec_h264_recycle,
|
||||
+ .eos_sequence = codec_h264_eos_sequence,
|
||||
+ .resume = codec_h264_resume,
|
||||
+};
|
||||
diff --git a/drivers/staging/media/meson/vdec/codec_h264.h b/drivers/staging/media/meson/vdec/codec_h264.h
|
||||
new file mode 100644
|
||||
index 000000000000..7cb4fb86ff36
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/codec_h264.h
|
||||
@@ -0,0 +1,14 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2019 BayLibre, SAS
|
||||
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_CODEC_H264_H_
|
||||
+#define __MESON_VDEC_CODEC_H264_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+extern struct amvdec_codec_ops codec_h264_ops;
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
index 066d4a055894..e9356a46828f 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_platform.c
|
||||
@@ -9,9 +9,22 @@
|
||||
|
||||
#include "vdec_1.h"
|
||||
#include "codec_mpeg12.h"
|
||||
+#include "codec_h264.h"
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 2,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/vdec/gxbb_h264.bin",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED |
|
||||
+ V4L2_FMT_FLAG_DYN_RESOLUTION,
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -38,6 +51,18 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 2,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/vdec/gxl_h264.bin",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED |
|
||||
+ V4L2_FMT_FLAG_DYN_RESOLUTION,
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -64,6 +89,18 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 2,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/vdec/gxm_h264.bin",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED |
|
||||
+ V4L2_FMT_FLAG_DYN_RESOLUTION,
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -90,6 +127,18 @@ static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_g12a[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 2,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/vdec/g12a_h264.bin",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED |
|
||||
+ V4L2_FMT_FLAG_DYN_RESOLUTION,
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -116,6 +165,18 @@ static const struct amvdec_format vdec_formats_g12a[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_sm1[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 2,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/vdec/g12a_h264.bin",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
|
||||
+ .flags = V4L2_FMT_FLAG_COMPRESSED |
|
||||
+ V4L2_FMT_FLAG_DYN_RESOLUTION,
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,77 +0,0 @@
|
||||
From 9161e4a4818559fcacbe729957a98ddd554c846c Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 4 Dec 2019 10:40:13 +0100
|
||||
Subject: [PATCH 110/146] FROMLIST: media: meson: vdec: align stride on 32
|
||||
bytes
|
||||
|
||||
The HEVC/VP9 aligns the plane stride on 32, so align the planes stride
|
||||
for all codecs to 32 to satisfy HEVC/VP9 decoding using the "HEVC" HW.
|
||||
|
||||
This fixes VP9 decoding of streams with following (not limited) widths:
|
||||
- 264
|
||||
-288
|
||||
- 350
|
||||
- 352
|
||||
- 472
|
||||
- 480
|
||||
- 528
|
||||
- 600
|
||||
- 720
|
||||
- 800
|
||||
- 848
|
||||
- 1440
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/staging/media/meson/vdec/vdec.c | 10 +++++-----
|
||||
drivers/staging/media/meson/vdec/vdec_helpers.c | 4 ++--
|
||||
2 files changed, 7 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
|
||||
index 92f0258868b1..bfca4c82aa56 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec.c
|
||||
@@ -528,20 +528,20 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
|
||||
memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
|
||||
if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) {
|
||||
pfmt[0].sizeimage = output_size;
|
||||
- pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
|
||||
+ pfmt[0].bytesperline = ALIGN(pixmp->width, 32);
|
||||
|
||||
pfmt[1].sizeimage = output_size / 2;
|
||||
- pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
|
||||
+ pfmt[1].bytesperline = ALIGN(pixmp->width, 32);
|
||||
pixmp->num_planes = 2;
|
||||
} else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) {
|
||||
pfmt[0].sizeimage = output_size;
|
||||
- pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
|
||||
+ pfmt[0].bytesperline = ALIGN(pixmp->width, 32);
|
||||
|
||||
pfmt[1].sizeimage = output_size / 4;
|
||||
- pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2;
|
||||
+ pfmt[1].bytesperline = ALIGN(pixmp->width, 32) / 2;
|
||||
|
||||
pfmt[2].sizeimage = output_size / 2;
|
||||
- pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
|
||||
+ pfmt[2].bytesperline = ALIGN(pixmp->width, 32) / 2;
|
||||
pixmp->num_planes = 3;
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
index a4970ec1bf2e..3f7929c54dc6 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
@@ -154,8 +154,8 @@ int amvdec_set_canvases(struct amvdec_session *sess,
|
||||
{
|
||||
struct v4l2_m2m_buffer *buf;
|
||||
u32 pixfmt = sess->pixfmt_cap;
|
||||
- u32 width = ALIGN(sess->width, 64);
|
||||
- u32 height = ALIGN(sess->height, 64);
|
||||
+ u32 width = ALIGN(sess->width, 32);
|
||||
+ u32 height = ALIGN(sess->height, 32);
|
||||
u32 reg_cur = reg_base[0];
|
||||
u32 reg_num_cur = 0;
|
||||
u32 reg_base_cur = 0;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,73 +0,0 @@
|
||||
From 09c3c7a5c19c353272145a47b679356eadb5bc7c Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Sun, 21 Oct 2018 15:15:26 +0200
|
||||
Subject: [PATCH 111/146] FROMLIST: media: meson: vdec: add helpers for
|
||||
lossless framebuffer compression buffers
|
||||
|
||||
Add helpers to support the lossless framebuffer compression format that
|
||||
will be used in HEVC & VP9 decoders when decoding 10bit content for
|
||||
downsampling to 8bit NV12 and later proper compressed buffer support.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../staging/media/meson/vdec/vdec_helpers.c | 27 +++++++++++++++++++
|
||||
.../staging/media/meson/vdec/vdec_helpers.h | 4 +++
|
||||
2 files changed, 31 insertions(+)
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
index 3f7929c54dc6..caec0fb60338 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.c
|
||||
@@ -50,6 +50,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amvdec_write_parser);
|
||||
|
||||
+/* 4 KiB per 64x32 block */
|
||||
+u32 amvdec_am21c_body_size(u32 width, u32 height)
|
||||
+{
|
||||
+ u32 width_64 = ALIGN(width, 64) / 64;
|
||||
+ u32 height_32 = ALIGN(height, 32) / 32;
|
||||
+
|
||||
+ return SZ_4K * width_64 * height_32;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_body_size);
|
||||
+
|
||||
+/* 32 bytes per 128x64 block */
|
||||
+u32 amvdec_am21c_head_size(u32 width, u32 height)
|
||||
+{
|
||||
+ u32 width_128 = ALIGN(width, 128) / 128;
|
||||
+ u32 height_64 = ALIGN(height, 64) / 64;
|
||||
+
|
||||
+ return 32 * width_128 * height_64;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_head_size);
|
||||
+
|
||||
+u32 amvdec_am21c_size(u32 width, u32 height)
|
||||
+{
|
||||
+ return ALIGN(amvdec_am21c_body_size(width, height) +
|
||||
+ amvdec_am21c_head_size(width, height), SZ_64K);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_size);
|
||||
+
|
||||
static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
|
||||
{
|
||||
int ret;
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
index 165e6293ffba..cfaed52ab526 100644
|
||||
--- a/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_helpers.h
|
||||
@@ -27,6 +27,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
|
||||
u32 amvdec_read_parser(struct amvdec_core *core, u32 reg);
|
||||
void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val);
|
||||
|
||||
+u32 amvdec_am21c_body_size(u32 width, u32 height);
|
||||
+u32 amvdec_am21c_head_size(u32 width, u32 height);
|
||||
+u32 amvdec_am21c_size(u32 width, u32 height);
|
||||
+
|
||||
/**
|
||||
* amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding
|
||||
*
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,893 +0,0 @@
|
||||
From 9842aec2ae55857deaee9f7eb994be6cc8d54590 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 18:48:35 +0200
|
||||
Subject: [PATCH 112/146] FROMLIST: media: meson: vdec: add common HEVC decoder
|
||||
support
|
||||
|
||||
Add support for the HEVC & VP9 common decoder support, handling
|
||||
Amlogic GXBB, GXL, G12A and SM1 platforms.
|
||||
|
||||
This handles the "HEVC" hw decoder used for HEVC and VP9, and will be
|
||||
using in the new H264 multi-instance decoder for G12A & SM1 platforms.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/staging/media/meson/vdec/Makefile | 4 +-
|
||||
.../media/meson/vdec/codec_hevc_common.c | 286 ++++++++++++++++++
|
||||
.../media/meson/vdec/codec_hevc_common.h | 77 +++++
|
||||
drivers/staging/media/meson/vdec/hevc_regs.h | 211 +++++++++++++
|
||||
drivers/staging/media/meson/vdec/vdec_hevc.c | 231 ++++++++++++++
|
||||
drivers/staging/media/meson/vdec/vdec_hevc.h | 13 +
|
||||
6 files changed, 820 insertions(+), 2 deletions(-)
|
||||
create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.c
|
||||
create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.h
|
||||
create mode 100644 drivers/staging/media/meson/vdec/hevc_regs.h
|
||||
create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.c
|
||||
create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.h
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile
|
||||
index 711d990c760e..f55b6e625034 100644
|
||||
--- a/drivers/staging/media/meson/vdec/Makefile
|
||||
+++ b/drivers/staging/media/meson/vdec/Makefile
|
||||
@@ -2,7 +2,7 @@
|
||||
# Makefile for Amlogic meson video decoder driver
|
||||
|
||||
meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
|
||||
-meson-vdec-objs += vdec_1.o
|
||||
-meson-vdec-objs += codec_mpeg12.o codec_h264.o
|
||||
+meson-vdec-objs += vdec_1.o vdec_hevc.o
|
||||
+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
|
||||
diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c
|
||||
new file mode 100644
|
||||
index 000000000000..335bcba062ac
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c
|
||||
@@ -0,0 +1,286 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <mjourdan@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#include <media/v4l2-mem2mem.h>
|
||||
+#include <media/videobuf2-dma-contig.h>
|
||||
+
|
||||
+#include "codec_hevc_common.h"
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "hevc_regs.h"
|
||||
+
|
||||
+#define MMU_COMPRESS_HEADER_SIZE 0x48000
|
||||
+#define MMU_MAP_SIZE 0x4800
|
||||
+
|
||||
+/* Configure decode head read mode */
|
||||
+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height);
|
||||
+ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height);
|
||||
+
|
||||
+ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
|
||||
+ /* Enable 2-plane reference read mode */
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31));
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (codec_hevc_use_mmu(core->platform->revision,
|
||||
+ sess->pixfmt_cap, is_10bit))
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4));
|
||||
+ else
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0);
|
||||
+
|
||||
+ if (core->platform->revision < VDEC_REVISION_SM1)
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32);
|
||||
+ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size);
|
||||
+ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size);
|
||||
+ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head);
|
||||
+
|
||||
+static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ int is_10bit)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct v4l2_m2m_buffer *buf;
|
||||
+ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
|
||||
+ dma_addr_t buf_y_paddr = 0;
|
||||
+ dma_addr_t buf_uv_paddr = 0;
|
||||
+ u32 idx = 0;
|
||||
+ u32 val;
|
||||
+ int i;
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
|
||||
+
|
||||
+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
|
||||
+ struct vb2_buffer *vb = &buf->vb.vb2_buf;
|
||||
+
|
||||
+ idx = vb->index;
|
||||
+
|
||||
+ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit))
|
||||
+ buf_y_paddr = comm->fbc_buffer_paddr[idx];
|
||||
+ else
|
||||
+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
+
|
||||
+ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
|
||||
+ val = buf_y_paddr | (idx << 8) | 1;
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
|
||||
+ val);
|
||||
+ } else {
|
||||
+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
|
||||
+ val = buf_y_paddr | ((idx * 2) << 8) | 1;
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
|
||||
+ val);
|
||||
+ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1;
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
|
||||
+ val);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit))
|
||||
+ val = buf_y_paddr | (idx << 8) | 1;
|
||||
+ else
|
||||
+ val = buf_y_paddr | ((idx * 2) << 8) | 1;
|
||||
+
|
||||
+ /* Fill the remaining unused slots with the last buffer's Y addr */
|
||||
+ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i)
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val);
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
|
||||
+ for (i = 0; i < 32; ++i)
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
|
||||
+}
|
||||
+
|
||||
+static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ int is_10bit)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct v4l2_m2m_buffer *buf;
|
||||
+ u32 revision = core->platform->revision;
|
||||
+ u32 pixfmt_cap = sess->pixfmt_cap;
|
||||
+ int i;
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
|
||||
+ BIT(2) | BIT(1));
|
||||
+
|
||||
+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
|
||||
+ struct vb2_buffer *vb = &buf->vb.vb2_buf;
|
||||
+ dma_addr_t buf_y_paddr = 0;
|
||||
+ dma_addr_t buf_uv_paddr = 0;
|
||||
+ u32 idx = vb->index;
|
||||
+
|
||||
+ if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit))
|
||||
+ buf_y_paddr = comm->mmu_header_paddr[idx];
|
||||
+ else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit))
|
||||
+ buf_y_paddr = comm->fbc_buffer_paddr[idx];
|
||||
+ else
|
||||
+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
|
||||
+ buf_y_paddr >> 5);
|
||||
+
|
||||
+ if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) {
|
||||
+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
|
||||
+ buf_uv_paddr >> 5);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
|
||||
+ for (i = 0; i < 32; ++i)
|
||||
+ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
|
||||
+}
|
||||
+
|
||||
+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm)
|
||||
+{
|
||||
+ struct device *dev = sess->core->dev;
|
||||
+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
|
||||
+ if (comm->fbc_buffer_vaddr[i]) {
|
||||
+ dma_free_coherent(dev, am21_size,
|
||||
+ comm->fbc_buffer_vaddr[i],
|
||||
+ comm->fbc_buffer_paddr[i]);
|
||||
+ comm->fbc_buffer_vaddr[i] = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers);
|
||||
+
|
||||
+static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm)
|
||||
+{
|
||||
+ struct device *dev = sess->core->dev;
|
||||
+ struct v4l2_m2m_buffer *buf;
|
||||
+ u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
|
||||
+
|
||||
+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
|
||||
+ u32 idx = buf->vb.vb2_buf.index;
|
||||
+ dma_addr_t paddr;
|
||||
+ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!vaddr) {
|
||||
+ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx);
|
||||
+ codec_hevc_free_fbc_buffers(sess, comm);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ comm->fbc_buffer_vaddr[idx] = vaddr;
|
||||
+ comm->fbc_buffer_paddr[idx] = paddr;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void codec_hevc_free_mmu_headers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm)
|
||||
+{
|
||||
+ struct device *dev = sess->core->dev;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
|
||||
+ if (comm->mmu_header_vaddr[i]) {
|
||||
+ dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
|
||||
+ comm->mmu_header_vaddr[i],
|
||||
+ comm->mmu_header_paddr[i]);
|
||||
+ comm->mmu_header_vaddr[i] = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (comm->mmu_map_vaddr) {
|
||||
+ dma_free_coherent(dev, MMU_MAP_SIZE,
|
||||
+ comm->mmu_map_vaddr,
|
||||
+ comm->mmu_map_paddr);
|
||||
+ comm->mmu_map_vaddr = NULL;
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers);
|
||||
+
|
||||
+static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm)
|
||||
+{
|
||||
+ struct device *dev = sess->core->dev;
|
||||
+ struct v4l2_m2m_buffer *buf;
|
||||
+
|
||||
+ comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE,
|
||||
+ &comm->mmu_map_paddr,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!comm->mmu_map_vaddr)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
|
||||
+ u32 idx = buf->vb.vb2_buf.index;
|
||||
+ dma_addr_t paddr;
|
||||
+ void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
|
||||
+ &paddr, GFP_KERNEL);
|
||||
+ if (!vaddr) {
|
||||
+ dev_err(dev, "Couldn't allocate MMU header %u\n", idx);
|
||||
+ codec_hevc_free_mmu_headers(sess, comm);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ comm->mmu_header_vaddr[idx] = vaddr;
|
||||
+ comm->mmu_header_paddr[idx] = paddr;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int codec_hevc_setup_buffers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ int is_10bit)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) {
|
||||
+ ret = codec_hevc_alloc_fbc_buffers(sess, comm);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (codec_hevc_use_mmu(core->platform->revision,
|
||||
+ sess->pixfmt_cap, is_10bit)) {
|
||||
+ ret = codec_hevc_alloc_mmu_headers(sess, comm);
|
||||
+ if (ret) {
|
||||
+ codec_hevc_free_fbc_buffers(sess, comm);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (core->platform->revision == VDEC_REVISION_GXBB)
|
||||
+ codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit);
|
||||
+ else
|
||||
+ codec_hevc_setup_buffers_gxl(sess, comm, is_10bit);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers);
|
||||
+
|
||||
+void codec_hevc_fill_mmu_map(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ struct vb2_buffer *vb)
|
||||
+{
|
||||
+ u32 size = amvdec_am21c_size(sess->width, sess->height);
|
||||
+ u32 nb_pages = size / PAGE_SIZE;
|
||||
+ u32 *mmu_map = comm->mmu_map_vaddr;
|
||||
+ u32 first_page;
|
||||
+ u32 i;
|
||||
+
|
||||
+ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
|
||||
+ first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT;
|
||||
+ else
|
||||
+ first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT;
|
||||
+
|
||||
+ for (i = 0; i < nb_pages; ++i)
|
||||
+ mmu_map[i] = first_page + i;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map);
|
||||
diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.h b/drivers/staging/media/meson/vdec/codec_hevc_common.h
|
||||
new file mode 100644
|
||||
index 000000000000..de16d2e43061
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/codec_hevc_common.h
|
||||
@@ -0,0 +1,77 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 BayLibre, SAS
|
||||
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_HEVC_COMMON_H_
|
||||
+#define __MESON_VDEC_HEVC_COMMON_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+#define PARSER_CMD_SKIP_CFG_0 0x0000090b
|
||||
+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f
|
||||
+#define PARSER_CMD_SKIP_CFG_2 0x001b1910
|
||||
+static const u16 vdec_hevc_parser_cmd[] = {
|
||||
+ 0x0401, 0x8401, 0x0800, 0x0402,
|
||||
+ 0x9002, 0x1423, 0x8CC3, 0x1423,
|
||||
+ 0x8804, 0x9825, 0x0800, 0x04FE,
|
||||
+ 0x8406, 0x8411, 0x1800, 0x8408,
|
||||
+ 0x8409, 0x8C2A, 0x9C2B, 0x1C00,
|
||||
+ 0x840F, 0x8407, 0x8000, 0x8408,
|
||||
+ 0x2000, 0xA800, 0x8410, 0x04DE,
|
||||
+ 0x840C, 0x840D, 0xAC00, 0xA000,
|
||||
+ 0x08C0, 0x08E0, 0xA40E, 0xFC00,
|
||||
+ 0x7C00
|
||||
+};
|
||||
+
|
||||
+#define MAX_REF_PIC_NUM 24
|
||||
+
|
||||
+struct codec_hevc_common {
|
||||
+ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM];
|
||||
+ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM];
|
||||
+
|
||||
+ void *mmu_header_vaddr[MAX_REF_PIC_NUM];
|
||||
+ dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM];
|
||||
+
|
||||
+ void *mmu_map_vaddr;
|
||||
+ dma_addr_t mmu_map_paddr;
|
||||
+};
|
||||
+
|
||||
+/* Returns 1 if we must use framebuffer compression */
|
||||
+static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit)
|
||||
+{
|
||||
+ /* TOFIX: Handle Amlogic Compressed buffer for 8bit also */
|
||||
+ return is_10bit;
|
||||
+}
|
||||
+
|
||||
+/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */
|
||||
+static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit)
|
||||
+{
|
||||
+ return is_10bit;
|
||||
+}
|
||||
+
|
||||
+/* Returns 1 if we are decoding using the IOMMU */
|
||||
+static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit)
|
||||
+{
|
||||
+ return revision >= VDEC_REVISION_G12A &&
|
||||
+ codec_hevc_use_fbc(pixfmt, is_10bit);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Configure decode head read mode
|
||||
+ */
|
||||
+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit);
|
||||
+
|
||||
+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm);
|
||||
+
|
||||
+int codec_hevc_setup_buffers(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ int is_10bit);
|
||||
+
|
||||
+void codec_hevc_fill_mmu_map(struct amvdec_session *sess,
|
||||
+ struct codec_hevc_common *comm,
|
||||
+ struct vb2_buffer *vb);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h
|
||||
new file mode 100644
|
||||
index 000000000000..55c1a80b955a
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/hevc_regs.h
|
||||
@@ -0,0 +1,211 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_HEVC_REGS_H_
|
||||
+#define __MESON_VDEC_HEVC_REGS_H_
|
||||
+
|
||||
+#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024
|
||||
+
|
||||
+#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4
|
||||
+#define HEVC_ASSIST_MBOX1_MASK 0xc1d8
|
||||
+
|
||||
+#define HEVC_ASSIST_SCRATCH_0 0xc300
|
||||
+#define HEVC_ASSIST_SCRATCH_1 0xc304
|
||||
+#define HEVC_ASSIST_SCRATCH_2 0xc308
|
||||
+#define HEVC_ASSIST_SCRATCH_3 0xc30c
|
||||
+#define HEVC_ASSIST_SCRATCH_4 0xc310
|
||||
+#define HEVC_ASSIST_SCRATCH_5 0xc314
|
||||
+#define HEVC_ASSIST_SCRATCH_6 0xc318
|
||||
+#define HEVC_ASSIST_SCRATCH_7 0xc31c
|
||||
+#define HEVC_ASSIST_SCRATCH_8 0xc320
|
||||
+#define HEVC_ASSIST_SCRATCH_9 0xc324
|
||||
+#define HEVC_ASSIST_SCRATCH_A 0xc328
|
||||
+#define HEVC_ASSIST_SCRATCH_B 0xc32c
|
||||
+#define HEVC_ASSIST_SCRATCH_C 0xc330
|
||||
+#define HEVC_ASSIST_SCRATCH_D 0xc334
|
||||
+#define HEVC_ASSIST_SCRATCH_E 0xc338
|
||||
+#define HEVC_ASSIST_SCRATCH_F 0xc33c
|
||||
+#define HEVC_ASSIST_SCRATCH_G 0xc340
|
||||
+#define HEVC_ASSIST_SCRATCH_H 0xc344
|
||||
+#define HEVC_ASSIST_SCRATCH_I 0xc348
|
||||
+#define HEVC_ASSIST_SCRATCH_J 0xc34c
|
||||
+#define HEVC_ASSIST_SCRATCH_K 0xc350
|
||||
+#define HEVC_ASSIST_SCRATCH_L 0xc354
|
||||
+#define HEVC_ASSIST_SCRATCH_M 0xc358
|
||||
+#define HEVC_ASSIST_SCRATCH_N 0xc35c
|
||||
+
|
||||
+#define HEVC_PARSER_VERSION 0xc400
|
||||
+#define HEVC_STREAM_CONTROL 0xc404
|
||||
+#define HEVC_STREAM_START_ADDR 0xc408
|
||||
+#define HEVC_STREAM_END_ADDR 0xc40c
|
||||
+#define HEVC_STREAM_WR_PTR 0xc410
|
||||
+#define HEVC_STREAM_RD_PTR 0xc414
|
||||
+#define HEVC_STREAM_LEVEL 0xc418
|
||||
+#define HEVC_STREAM_FIFO_CTL 0xc41c
|
||||
+#define HEVC_SHIFT_CONTROL 0xc420
|
||||
+#define HEVC_SHIFT_STARTCODE 0xc424
|
||||
+#define HEVC_SHIFT_EMULATECODE 0xc428
|
||||
+#define HEVC_SHIFT_STATUS 0xc42c
|
||||
+#define HEVC_SHIFTED_DATA 0xc430
|
||||
+#define HEVC_SHIFT_BYTE_COUNT 0xc434
|
||||
+#define HEVC_SHIFT_COMMAND 0xc438
|
||||
+#define HEVC_ELEMENT_RESULT 0xc43c
|
||||
+#define HEVC_CABAC_CONTROL 0xc440
|
||||
+#define HEVC_PARSER_SLICE_INFO 0xc444
|
||||
+#define HEVC_PARSER_CMD_WRITE 0xc448
|
||||
+#define HEVC_PARSER_CORE_CONTROL 0xc44c
|
||||
+#define HEVC_PARSER_CMD_FETCH 0xc450
|
||||
+#define HEVC_PARSER_CMD_STATUS 0xc454
|
||||
+#define HEVC_PARSER_LCU_INFO 0xc458
|
||||
+#define HEVC_PARSER_HEADER_INFO 0xc45c
|
||||
+#define HEVC_PARSER_INT_CONTROL 0xc480
|
||||
+#define HEVC_PARSER_INT_STATUS 0xc484
|
||||
+#define HEVC_PARSER_IF_CONTROL 0xc488
|
||||
+#define HEVC_PARSER_PICTURE_SIZE 0xc48c
|
||||
+#define HEVC_PARSER_LCU_START 0xc490
|
||||
+#define HEVC_PARSER_HEADER_INFO2 0xc494
|
||||
+#define HEVC_PARSER_QUANT_READ 0xc498
|
||||
+#define HEVC_PARSER_RESERVED_27 0xc49c
|
||||
+#define HEVC_PARSER_CMD_SKIP_0 0xc4a0
|
||||
+#define HEVC_PARSER_CMD_SKIP_1 0xc4a4
|
||||
+#define HEVC_PARSER_CMD_SKIP_2 0xc4a8
|
||||
+#define HEVC_SAO_IF_STATUS 0xc4c0
|
||||
+#define HEVC_SAO_IF_DATA_Y 0xc4c4
|
||||
+#define HEVC_SAO_IF_DATA_U 0xc4c8
|
||||
+#define HEVC_SAO_IF_DATA_V 0xc4cc
|
||||
+#define HEVC_STREAM_SWAP_ADDR 0xc4d0
|
||||
+#define HEVC_STREAM_SWAP_CTRL 0xc4d4
|
||||
+#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8
|
||||
+#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc
|
||||
+#define HEVC_SAO_IF_WAIT_CNT 0xc4e0
|
||||
+
|
||||
+#define HEVC_MPRED_VERSION 0xc800
|
||||
+#define HEVC_MPRED_CTRL0 0xc804
|
||||
+ #define MPRED_CTRL0_NEW_PIC BIT(2)
|
||||
+ #define MPRED_CTRL0_NEW_TILE BIT(3)
|
||||
+ #define MPRED_CTRL0_NEW_SLI_SEG BIT(4)
|
||||
+ #define MPRED_CTRL0_TMVP BIT(5)
|
||||
+ #define MPRED_CTRL0_LDC BIT(6)
|
||||
+ #define MPRED_CTRL0_COL_FROM_L0 BIT(7)
|
||||
+ #define MPRED_CTRL0_ABOVE_EN BIT(9)
|
||||
+ #define MPRED_CTRL0_MV_WR_EN BIT(10)
|
||||
+ #define MPRED_CTRL0_MV_RD_EN BIT(11)
|
||||
+ #define MPRED_CTRL0_BUF_LINEAR BIT(13)
|
||||
+#define HEVC_MPRED_CTRL1 0xc808
|
||||
+#define HEVC_MPRED_INT_EN 0xc80c
|
||||
+#define HEVC_MPRED_INT_STATUS 0xc810
|
||||
+#define HEVC_MPRED_PIC_SIZE 0xc814
|
||||
+#define HEVC_MPRED_PIC_SIZE_LCU 0xc818
|
||||
+#define HEVC_MPRED_TILE_START 0xc81c
|
||||
+#define HEVC_MPRED_TILE_SIZE_LCU 0xc820
|
||||
+#define HEVC_MPRED_REF_NUM 0xc824
|
||||
+#define HEVC_MPRED_REF_EN_L0 0xc830
|
||||
+#define HEVC_MPRED_REF_EN_L1 0xc834
|
||||
+#define HEVC_MPRED_COLREF_EN_L0 0xc838
|
||||
+#define HEVC_MPRED_COLREF_EN_L1 0xc83c
|
||||
+#define HEVC_MPRED_AXI_WCTRL 0xc840
|
||||
+#define HEVC_MPRED_AXI_RCTRL 0xc844
|
||||
+#define HEVC_MPRED_ABV_START_ADDR 0xc848
|
||||
+#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c
|
||||
+#define HEVC_MPRED_MV_RD_START_ADDR 0xc850
|
||||
+#define HEVC_MPRED_MV_WPTR 0xc854
|
||||
+#define HEVC_MPRED_MV_RPTR 0xc858
|
||||
+#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c
|
||||
+#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860
|
||||
+#define HEVC_MPRED_CURR_LCU 0xc864
|
||||
+#define HEVC_MPRED_ABV_WPTR 0xc868
|
||||
+#define HEVC_MPRED_ABV_RPTR 0xc86c
|
||||
+#define HEVC_MPRED_CTRL2 0xc870
|
||||
+#define HEVC_MPRED_CTRL3 0xc874
|
||||
+#define HEVC_MPRED_L0_REF00_POC 0xc880
|
||||
+#define HEVC_MPRED_L1_REF00_POC 0xc8c0
|
||||
+
|
||||
+#define HEVC_MPRED_CUR_POC 0xc980
|
||||
+#define HEVC_MPRED_COL_POC 0xc984
|
||||
+#define HEVC_MPRED_MV_RD_END_ADDR 0xc988
|
||||
+
|
||||
+#define HEVC_MSP 0xcc00
|
||||
+#define HEVC_MPSR 0xcc04
|
||||
+#define HEVC_MCPU_INTR_MSK 0xcc10
|
||||
+#define HEVC_MCPU_INTR_REQ 0xcc14
|
||||
+#define HEVC_CPSR 0xcc84
|
||||
+
|
||||
+#define HEVC_IMEM_DMA_CTRL 0xcd00
|
||||
+#define HEVC_IMEM_DMA_ADR 0xcd04
|
||||
+#define HEVC_IMEM_DMA_COUNT 0xcd08
|
||||
+
|
||||
+#define HEVCD_IPP_TOP_CNTL 0xd000
|
||||
+#define HEVCD_IPP_LINEBUFF_BASE 0xd024
|
||||
+#define HEVCD_IPP_AXIIF_CONFIG 0xd02c
|
||||
+
|
||||
+#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180
|
||||
+#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184
|
||||
+#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190
|
||||
+
|
||||
+#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300
|
||||
+#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304
|
||||
+#define HEVCD_MPP_DECOMP_CTL1 0xd308
|
||||
+#define HEVCD_MPP_DECOMP_CTL2 0xd30c
|
||||
+#define HEVCD_MCRCC_CTL1 0xd3c0
|
||||
+#define HEVCD_MCRCC_CTL2 0xd3c4
|
||||
+#define HEVCD_MCRCC_CTL3 0xd3c8
|
||||
+
|
||||
+#define HEVC_DBLK_CFG0 0xd400
|
||||
+#define HEVC_DBLK_CFG1 0xd404
|
||||
+#define HEVC_DBLK_CFG2 0xd408
|
||||
+#define HEVC_DBLK_CFG3 0xd40c
|
||||
+#define HEVC_DBLK_CFG4 0xd410
|
||||
+#define HEVC_DBLK_CFG5 0xd414
|
||||
+#define HEVC_DBLK_CFG6 0xd418
|
||||
+#define HEVC_DBLK_CFG7 0xd41c
|
||||
+#define HEVC_DBLK_CFG8 0xd420
|
||||
+#define HEVC_DBLK_CFG9 0xd424
|
||||
+#define HEVC_DBLK_CFGA 0xd428
|
||||
+#define HEVC_DBLK_STS0 0xd42c
|
||||
+#define HEVC_DBLK_STS1 0xd430
|
||||
+#define HEVC_DBLK_CFGE 0xd438
|
||||
+
|
||||
+#define HEVC_SAO_VERSION 0xd800
|
||||
+#define HEVC_SAO_CTRL0 0xd804
|
||||
+#define HEVC_SAO_CTRL1 0xd808
|
||||
+#define HEVC_SAO_PIC_SIZE 0xd814
|
||||
+#define HEVC_SAO_PIC_SIZE_LCU 0xd818
|
||||
+#define HEVC_SAO_TILE_START 0xd81c
|
||||
+#define HEVC_SAO_TILE_SIZE_LCU 0xd820
|
||||
+#define HEVC_SAO_Y_START_ADDR 0xd82c
|
||||
+#define HEVC_SAO_Y_LENGTH 0xd830
|
||||
+#define HEVC_SAO_C_START_ADDR 0xd834
|
||||
+#define HEVC_SAO_C_LENGTH 0xd838
|
||||
+#define HEVC_SAO_Y_WPTR 0xd83c
|
||||
+#define HEVC_SAO_C_WPTR 0xd840
|
||||
+#define HEVC_SAO_ABV_START_ADDR 0xd844
|
||||
+#define HEVC_SAO_VB_WR_START_ADDR 0xd848
|
||||
+#define HEVC_SAO_VB_RD_START_ADDR 0xd84c
|
||||
+#define HEVC_SAO_ABV_WPTR 0xd850
|
||||
+#define HEVC_SAO_ABV_RPTR 0xd854
|
||||
+#define HEVC_SAO_VB_WPTR 0xd858
|
||||
+#define HEVC_SAO_VB_RPTR 0xd85c
|
||||
+#define HEVC_SAO_CTRL2 0xd880
|
||||
+#define HEVC_SAO_CTRL3 0xd884
|
||||
+#define HEVC_SAO_CTRL4 0xd888
|
||||
+#define HEVC_SAO_CTRL5 0xd88c
|
||||
+#define HEVC_SAO_CTRL6 0xd890
|
||||
+#define HEVC_SAO_CTRL7 0xd894
|
||||
+#define HEVC_CM_BODY_START_ADDR 0xd898
|
||||
+#define HEVC_CM_BODY_LENGTH 0xd89c
|
||||
+#define HEVC_CM_HEADER_START_ADDR 0xd8a0
|
||||
+#define HEVC_CM_HEADER_LENGTH 0xd8a4
|
||||
+#define HEVC_CM_HEADER_OFFSET 0xd8ac
|
||||
+#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8
|
||||
+#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec
|
||||
+
|
||||
+#define HEVC_IQIT_CLK_RST_CTRL 0xdc00
|
||||
+#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08
|
||||
+#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c
|
||||
+#define HEVC_IQIT_SCALELUT_DATA 0xdc10
|
||||
+
|
||||
+#define HEVC_PSCALE_CTRL 0xe444
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c
|
||||
new file mode 100644
|
||||
index 000000000000..af41215e106c
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_hevc.c
|
||||
@@ -0,0 +1,231 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ *
|
||||
+ * VDEC_HEVC is a video decoding block that allows decoding of
|
||||
+ * HEVC, VP9
|
||||
+ */
|
||||
+
|
||||
+#include <linux/firmware.h>
|
||||
+#include <linux/clk.h>
|
||||
+
|
||||
+#include "vdec_1.h"
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "hevc_regs.h"
|
||||
+#include "dos_regs.h"
|
||||
+
|
||||
+/* AO Registers */
|
||||
+#define AO_RTI_GEN_PWR_SLEEP0 0xe8
|
||||
+#define AO_RTI_GEN_PWR_ISO0 0xec
|
||||
+ #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6))
|
||||
+ #define GEN_PWR_VDEC_HEVC_SM1 (BIT(2))
|
||||
+
|
||||
+#define MC_SIZE (4096 * 4)
|
||||
+
|
||||
+static int vdec_hevc_load_firmware(struct amvdec_session *sess,
|
||||
+ const char *fwname)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct device *dev = core->dev_dec;
|
||||
+ const struct firmware *fw;
|
||||
+ static void *mc_addr;
|
||||
+ static dma_addr_t mc_addr_map;
|
||||
+ int ret;
|
||||
+ u32 i = 100;
|
||||
+
|
||||
+ ret = request_firmware(&fw, fwname, dev);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(dev, "Unable to request firmware %s\n", fwname);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (fw->size < MC_SIZE) {
|
||||
+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
|
||||
+ fw->size, MC_SIZE);
|
||||
+ ret = -EINVAL;
|
||||
+ goto release_firmware;
|
||||
+ }
|
||||
+
|
||||
+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!mc_addr) {
|
||||
+ dev_err(dev, "Failed allocating memory for firmware loading\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto release_firmware;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(mc_addr, fw->data, MC_SIZE);
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVC_MPSR, 0);
|
||||
+ amvdec_write_dos(core, HEVC_CPSR, 0);
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map);
|
||||
+ amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4);
|
||||
+ amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
|
||||
+
|
||||
+ while (i && (readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000))
|
||||
+ i--;
|
||||
+
|
||||
+ if (i == 0) {
|
||||
+ dev_err(dev, "Firmware load fail (DMA hang?)\n");
|
||||
+ ret = -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
|
||||
+release_firmware:
|
||||
+ release_firmware(fw);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void vdec_hevc_stbuf_init(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_CONTROL,
|
||||
+ amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_END_ADDR,
|
||||
+ sess->vififo_paddr + sess->vififo_size);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr);
|
||||
+}
|
||||
+
|
||||
+/* VDEC_HEVC specific ESPARSER configuration */
|
||||
+static void vdec_hevc_conf_esparser(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ /* set vififo_vbuf_rp_sel=>vdec_hevc */
|
||||
+ amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_CONTROL,
|
||||
+ amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3));
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_CONTROL,
|
||||
+ amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1);
|
||||
+ amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL,
|
||||
+ amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29));
|
||||
+}
|
||||
+
|
||||
+static u32 vdec_hevc_vififo_level(struct amvdec_session *sess)
|
||||
+{
|
||||
+ return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL);
|
||||
+}
|
||||
+
|
||||
+static int vdec_hevc_stop(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
|
||||
+
|
||||
+ /* Disable interrupt */
|
||||
+ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0);
|
||||
+ /* Disable firmware processor */
|
||||
+ amvdec_write_dos(core, HEVC_MPSR, 0);
|
||||
+
|
||||
+ if (sess->priv)
|
||||
+ codec_ops->stop(sess);
|
||||
+
|
||||
+ /* Enable VDEC_HEVC Isolation */
|
||||
+ if (core->platform->revision == VDEC_REVISION_SM1)
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1);
|
||||
+ else
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
|
||||
+ 0xc00, 0xc00);
|
||||
+
|
||||
+ /* VDEC_HEVC Memories */
|
||||
+ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL);
|
||||
+
|
||||
+ if (core->platform->revision == VDEC_REVISION_SM1)
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1);
|
||||
+ else
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
+ GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC);
|
||||
+
|
||||
+ clk_disable_unprepare(core->vdec_hevc_clk);
|
||||
+ if (core->platform->revision == VDEC_REVISION_G12A ||
|
||||
+ core->platform->revision == VDEC_REVISION_SM1)
|
||||
+ clk_disable_unprepare(core->vdec_hevcf_clk);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vdec_hevc_start(struct amvdec_session *sess)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
|
||||
+
|
||||
+ if (core->platform->revision == VDEC_REVISION_G12A ||
|
||||
+ core->platform->revision == VDEC_REVISION_SM1) {
|
||||
+ clk_set_rate(core->vdec_hevcf_clk, 666666666);
|
||||
+ ret = clk_prepare_enable(core->vdec_hevcf_clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ clk_set_rate(core->vdec_hevc_clk, 666666666);
|
||||
+ ret = clk_prepare_enable(core->vdec_hevc_clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (core->platform->revision == VDEC_REVISION_SM1)
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1, 0);
|
||||
+ else
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
|
||||
+ GEN_PWR_VDEC_HEVC, 0);
|
||||
+ udelay(10);
|
||||
+
|
||||
+ /* Reset VDEC_HEVC*/
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
|
||||
+
|
||||
+ amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff);
|
||||
+
|
||||
+ /* VDEC_HEVC Memories */
|
||||
+ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000);
|
||||
+
|
||||
+ /* Remove VDEC_HEVC Isolation */
|
||||
+ if (core->platform->revision == VDEC_REVISION_SM1)
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
|
||||
+ GEN_PWR_VDEC_HEVC_SM1, 0);
|
||||
+ else
|
||||
+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
|
||||
+ 0xc00, 0);
|
||||
+
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
|
||||
+
|
||||
+ vdec_hevc_stbuf_init(sess);
|
||||
+
|
||||
+ ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
|
||||
+ if (ret)
|
||||
+ goto stop;
|
||||
+
|
||||
+ ret = codec_ops->start(sess);
|
||||
+ if (ret)
|
||||
+ goto stop;
|
||||
+
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11));
|
||||
+ amvdec_write_dos(core, DOS_SW_RESET3, 0);
|
||||
+ amvdec_read_dos(core, DOS_SW_RESET3);
|
||||
+
|
||||
+ amvdec_write_dos(core, HEVC_MPSR, 1);
|
||||
+ /* Let the firmware settle */
|
||||
+ udelay(10);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+stop:
|
||||
+ vdec_hevc_stop(sess);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+struct amvdec_ops vdec_hevc_ops = {
|
||||
+ .start = vdec_hevc_start,
|
||||
+ .stop = vdec_hevc_stop,
|
||||
+ .conf_esparser = vdec_hevc_conf_esparser,
|
||||
+ .vififo_level = vdec_hevc_vififo_level,
|
||||
+};
|
||||
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.h b/drivers/staging/media/meson/vdec/vdec_hevc.h
|
||||
new file mode 100644
|
||||
index 000000000000..cd576a73a966
|
||||
--- /dev/null
|
||||
+++ b/drivers/staging/media/meson/vdec/vdec_hevc.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_VDEC_HEVC_H_
|
||||
+#define __MESON_VDEC_VDEC_HEVC_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+extern struct amvdec_ops vdec_hevc_ops;
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,216 +0,0 @@
|
||||
From 0852fcb597702d7b90feafa1ede9e358c8dc0fad Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Thu, 17 Jan 2019 16:59:11 +0100
|
||||
Subject: [PATCH 113/146] FROMLIST: media: meson: vdec: add VP9 input support
|
||||
|
||||
Amlogic VP9 decoder requires an additional 16-byte payload before every
|
||||
frame header.
|
||||
|
||||
The source buffer is updated in-place, then given to the Parser FIFO DMA.
|
||||
|
||||
The FIFO DMA copies the blocks into the 16MiB parser ring buffer, then parses
|
||||
and copies the slice into the decoder "workspace".
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/staging/media/meson/vdec/esparser.c | 150 +++++++++++++++++++-
|
||||
1 file changed, 146 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c
|
||||
index adc5c1e81a4c..4a9aad3fafeb 100644
|
||||
--- a/drivers/staging/media/meson/vdec/esparser.c
|
||||
+++ b/drivers/staging/media/meson/vdec/esparser.c
|
||||
@@ -52,6 +52,7 @@
|
||||
#define PARSER_VIDEO_HOLE 0x90
|
||||
|
||||
#define SEARCH_PATTERN_LEN 512
|
||||
+#define VP9_HEADER_SIZE 16
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(wq);
|
||||
static int search_done;
|
||||
@@ -74,14 +75,121 @@ static irqreturn_t esparser_isr(int irq, void *dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * VP9 frame headers need to be appended by a 16-byte long
|
||||
+ * Amlogic custom header
|
||||
+ */
|
||||
+static int vp9_update_header(struct amvdec_core *core, struct vb2_buffer *buf)
|
||||
+{
|
||||
+ u8 *dp;
|
||||
+ u8 marker;
|
||||
+ int dsize;
|
||||
+ int num_frames, cur_frame;
|
||||
+ int cur_mag, mag, mag_ptr;
|
||||
+ int frame_size[8], tot_frame_size[8];
|
||||
+ int total_datasize = 0;
|
||||
+ int new_frame_size;
|
||||
+ unsigned char *old_header = NULL;
|
||||
+
|
||||
+ dp = (uint8_t *)vb2_plane_vaddr(buf, 0);
|
||||
+ dsize = vb2_get_plane_payload(buf, 0);
|
||||
+
|
||||
+ if (dsize == vb2_plane_size(buf, 0)) {
|
||||
+ dev_warn(core->dev, "%s: unable to update header\n", __func__);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ marker = dp[dsize - 1];
|
||||
+ if ((marker & 0xe0) == 0xc0) {
|
||||
+ num_frames = (marker & 0x7) + 1;
|
||||
+ mag = ((marker >> 3) & 0x3) + 1;
|
||||
+ mag_ptr = dsize - mag * num_frames - 2;
|
||||
+ if (dp[mag_ptr] != marker)
|
||||
+ return 0;
|
||||
+
|
||||
+ mag_ptr++;
|
||||
+ for (cur_frame = 0; cur_frame < num_frames; cur_frame++) {
|
||||
+ frame_size[cur_frame] = 0;
|
||||
+ for (cur_mag = 0; cur_mag < mag; cur_mag++) {
|
||||
+ frame_size[cur_frame] |=
|
||||
+ (dp[mag_ptr] << (cur_mag * 8));
|
||||
+ mag_ptr++;
|
||||
+ }
|
||||
+ if (cur_frame == 0)
|
||||
+ tot_frame_size[cur_frame] =
|
||||
+ frame_size[cur_frame];
|
||||
+ else
|
||||
+ tot_frame_size[cur_frame] =
|
||||
+ tot_frame_size[cur_frame - 1] +
|
||||
+ frame_size[cur_frame];
|
||||
+ total_datasize += frame_size[cur_frame];
|
||||
+ }
|
||||
+ } else {
|
||||
+ num_frames = 1;
|
||||
+ frame_size[0] = dsize;
|
||||
+ tot_frame_size[0] = dsize;
|
||||
+ total_datasize = dsize;
|
||||
+ }
|
||||
+
|
||||
+ new_frame_size = total_datasize + num_frames * VP9_HEADER_SIZE;
|
||||
+
|
||||
+ if (new_frame_size >= vb2_plane_size(buf, 0)) {
|
||||
+ dev_warn(core->dev, "%s: unable to update header\n", __func__);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ for (cur_frame = num_frames - 1; cur_frame >= 0; cur_frame--) {
|
||||
+ int framesize = frame_size[cur_frame];
|
||||
+ int framesize_header = framesize + 4;
|
||||
+ int oldframeoff = tot_frame_size[cur_frame] - framesize;
|
||||
+ int outheaderoff = oldframeoff + cur_frame * VP9_HEADER_SIZE;
|
||||
+ u8 *fdata = dp + outheaderoff;
|
||||
+ u8 *old_framedata = dp + oldframeoff;
|
||||
+
|
||||
+ memmove(fdata + VP9_HEADER_SIZE, old_framedata, framesize);
|
||||
+
|
||||
+ fdata[0] = (framesize_header >> 24) & 0xff;
|
||||
+ fdata[1] = (framesize_header >> 16) & 0xff;
|
||||
+ fdata[2] = (framesize_header >> 8) & 0xff;
|
||||
+ fdata[3] = (framesize_header >> 0) & 0xff;
|
||||
+ fdata[4] = ((framesize_header >> 24) & 0xff) ^ 0xff;
|
||||
+ fdata[5] = ((framesize_header >> 16) & 0xff) ^ 0xff;
|
||||
+ fdata[6] = ((framesize_header >> 8) & 0xff) ^ 0xff;
|
||||
+ fdata[7] = ((framesize_header >> 0) & 0xff) ^ 0xff;
|
||||
+ fdata[8] = 0;
|
||||
+ fdata[9] = 0;
|
||||
+ fdata[10] = 0;
|
||||
+ fdata[11] = 1;
|
||||
+ fdata[12] = 'A';
|
||||
+ fdata[13] = 'M';
|
||||
+ fdata[14] = 'L';
|
||||
+ fdata[15] = 'V';
|
||||
+
|
||||
+ if (!old_header) {
|
||||
+ /* nothing */
|
||||
+ } else if (old_header > fdata + 16 + framesize) {
|
||||
+ dev_dbg(core->dev, "%s: data has gaps, setting to 0\n",
|
||||
+ __func__);
|
||||
+ memset(fdata + 16 + framesize, 0,
|
||||
+ (old_header - fdata + 16 + framesize));
|
||||
+ } else if (old_header < fdata + 16 + framesize) {
|
||||
+ dev_err(core->dev, "%s: data overwritten\n", __func__);
|
||||
+ }
|
||||
+ old_header = fdata;
|
||||
+ }
|
||||
+
|
||||
+ return new_frame_size;
|
||||
+}
|
||||
+
|
||||
/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger
|
||||
* ISRs.
|
||||
* Also append a start code 000001ff at the end to trigger
|
||||
* the ESPARSER interrupt.
|
||||
*/
|
||||
-static u32 esparser_pad_start_code(struct amvdec_core *core, struct vb2_buffer *vb)
|
||||
+static u32 esparser_pad_start_code(struct amvdec_core *core,
|
||||
+ struct vb2_buffer *vb,
|
||||
+ u32 payload_size)
|
||||
{
|
||||
- u32 payload_size = vb2_get_plane_payload(vb, 0);
|
||||
u32 pad_size = 0;
|
||||
u8 *vaddr = vb2_plane_vaddr(vb, 0);
|
||||
|
||||
@@ -186,13 +294,35 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
|
||||
int ret;
|
||||
struct vb2_buffer *vb = &vbuf->vb2_buf;
|
||||
struct amvdec_core *core = sess->core;
|
||||
+ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
|
||||
u32 payload_size = vb2_get_plane_payload(vb, 0);
|
||||
dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
+ u32 num_dst_bufs = 0;
|
||||
u32 offset;
|
||||
u32 pad_size;
|
||||
|
||||
- if (esparser_vififo_get_free_space(sess) < payload_size)
|
||||
+ /*
|
||||
+ * When max ref frame is held by VP9, this should be -= 3 to prevent a
|
||||
+ * shortage of CAPTURE buffers on the decoder side.
|
||||
+ * For the future, a good enhancement of the way this is handled could
|
||||
+ * be to notify new capture buffers to the decoding modules, so that
|
||||
+ * they could pause when there is no capture buffer available and
|
||||
+ * resume on this notification.
|
||||
+ */
|
||||
+ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) {
|
||||
+ if (codec_ops->num_pending_bufs)
|
||||
+ num_dst_bufs = codec_ops->num_pending_bufs(sess);
|
||||
+
|
||||
+ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
|
||||
+ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9)
|
||||
+ num_dst_bufs -= 3;
|
||||
+
|
||||
+ if (esparser_vififo_get_free_space(sess) < payload_size ||
|
||||
+ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
|
||||
+ return -EAGAIN;
|
||||
+ } else if (esparser_vififo_get_free_space(sess) < payload_size) {
|
||||
return -EAGAIN;
|
||||
+ }
|
||||
|
||||
v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
|
||||
|
||||
@@ -206,7 +336,19 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
|
||||
vbuf->field = V4L2_FIELD_NONE;
|
||||
vbuf->sequence = sess->sequence_out++;
|
||||
|
||||
- pad_size = esparser_pad_start_code(core, vb);
|
||||
+ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) {
|
||||
+ payload_size = vp9_update_header(core, vb);
|
||||
+
|
||||
+ /* If unable to alter buffer to add headers */
|
||||
+ if (payload_size == 0) {
|
||||
+ amvdec_remove_ts(sess, vb->timestamp);
|
||||
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pad_size = esparser_pad_start_code(core, vb, payload_size);
|
||||
ret = esparser_write_data(core, phy, payload_size + pad_size);
|
||||
|
||||
if (ret <= 0) {
|
||||
--
|
||||
2.17.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +0,0 @@
|
||||
From 19c3b2dac2ce756a2f2ce1af1a2fd5cda807cfa3 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Sat, 19 Oct 2019 04:39:47 +0000
|
||||
Subject: [PATCH 119/146] FROMLIST: arm64: dts: meson-gxbb-odroid-c2: add
|
||||
rc-odroid ir keymap
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 76841f75a8a8..b1107d7ff32b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -288,6 +288,7 @@
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
pinctrl-names = "default";
|
||||
+ linux,rc-map-name = "rc-odroid";
|
||||
};
|
||||
|
||||
&gpio_ao {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From 50c13c5012dc6884799e2166a6452dc8c49683b1 Mon Sep 17 00:00:00 2001
|
||||
From: chewitt <github@chrishewitt.net>
|
||||
Date: Sat, 13 Apr 2019 06:18:39 +0000
|
||||
Subject: [PATCH 120/146] FROMLIST: arm64: dts: meson-gxbb-vega-s95: fix
|
||||
missing bindings and bluetooth node
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
|
||||
index 5eab3dfdbd55..3cacd32be986 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
#include "meson-gxbb.dtsi"
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+#include <dt-bindings/input/input.h>
|
||||
|
||||
/ {
|
||||
compatible = "tronsmart,vega-s95", "amlogic,meson-gxbb";
|
||||
@@ -124,7 +126,6 @@
|
||||
eth_phy0: ethernet-phy@0 {
|
||||
/* Realtek RTL8211F (0x001cc916) */
|
||||
reg = <0>;
|
||||
-
|
||||
reset-assert-us = <10000>;
|
||||
reset-deassert-us = <30000>;
|
||||
reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>;
|
||||
@@ -245,6 +246,9 @@
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>;
|
||||
+ max-speed = <2000000>;
|
||||
+ clocks = <&wifi32k>;
|
||||
+ clock-names = "lpo";
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,41 +0,0 @@
|
||||
From 6eb6ec4e705628b332b27d20afdf103460e2776c Mon Sep 17 00:00:00 2001
|
||||
From: chewitt <github@chrishewitt.net>
|
||||
Date: Mon, 15 Jul 2019 09:45:17 +0000
|
||||
Subject: [PATCH 121/146] FROMLIST: arm64: dts: meson-gxl-s905x-p212: add
|
||||
bluetooth nodes
|
||||
|
||||
Signed-off-by: Christian Hewitt <christian.hewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
index ba74f54c5b3f..9ad762197e2f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
@@ -16,7 +16,6 @@
|
||||
/ {
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
- serial1 = &uart_A;
|
||||
ethernet0 = ðmac;
|
||||
};
|
||||
|
||||
@@ -250,6 +249,14 @@
|
||||
pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
|
||||
pinctrl-names = "default";
|
||||
uart-has-rtscts;
|
||||
+
|
||||
+ bluetooth {
|
||||
+ compatible = "brcm,bcm43438-bt";
|
||||
+ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
|
||||
+ max-speed = <2000000>;
|
||||
+ clocks = <&wifi32k>;
|
||||
+ clock-names = "lpo";
|
||||
+ };
|
||||
};
|
||||
|
||||
&uart_AO {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,45 +0,0 @@
|
||||
From f8fd048da3c8ad0a9e39d4fc97f41d58000ada35 Mon Sep 17 00:00:00 2001
|
||||
From: chewitt <christianshewitt@gmail.com>
|
||||
Date: Wed, 19 Feb 2020 12:48:36 +0000
|
||||
Subject: [PATCH 122/146] FROMLIST: arm64: dts: meson: fix gxm-khadas-vim2 wifi
|
||||
|
||||
Fixes: adc52bf7ef16 ("arm64: dts: meson: fix mmc v2 chips max frequencies")
|
||||
|
||||
before
|
||||
|
||||
[ 6.418252] brcmfmac: F1 signature read @0x18000000=0x17224356
|
||||
[ 6.435663] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4356-sdio for chip BCM4356/2
|
||||
[ 6.551259] brcmfmac: brcmf_sdiod_ramrw: membytes transfer failed
|
||||
[ 6.551275] brcmfmac: brcmf_sdio_verifymemory: error -84 on reading 2048 membytes at 0x00184000
|
||||
[ 6.551352] brcmfmac: brcmf_sdio_download_firmware: dongle image file download failed
|
||||
|
||||
after
|
||||
|
||||
[ 6.657165] brcmfmac: F1 signature read @0x18000000=0x17224356
|
||||
[ 6.660807] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4356-sdio for chip BCM4356/2
|
||||
[ 6.918643] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac4356-sdio for chip BCM4356/2
|
||||
[ 6.918734] brcmfmac: brcmf_c_process_clm_blob: no clm_blob available (err=-2), device may have limited channels available
|
||||
[ 6.922724] brcmfmac: brcmf_c_preinit_dcmds: Firmware: BCM4356/2 wl0: Jun 16 2015 14:25:06 version 7.35.184.r1 (TOB) (r559293) FWID 01-b22ae69c
|
||||
|
||||
Suggested-by: Art Nikpal <email2tema@gmail.com>
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
index a25786c68def..dfa2abc55918 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
@@ -397,7 +397,7 @@
|
||||
#size-cells = <0>;
|
||||
|
||||
bus-width = <4>;
|
||||
- max-frequency = <50000000>;
|
||||
+ max-frequency = <60000000>;
|
||||
|
||||
non-removable;
|
||||
disable-wp;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,93 +0,0 @@
|
||||
From bbb089ffa58fb2ec94f9a73716c457b81e12f74e Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Fri, 21 Feb 2020 05:28:24 +0000
|
||||
Subject: [PATCH 123/146] FROMLIST: arm64: dts: meson: gxl-s905x-khadas-vim:
|
||||
add thermal zones
|
||||
|
||||
Add thermal zones to the VIM1 board so that a cooling fan can be driven
|
||||
using the i2c interface. Zone config is copied from the VIM2.
|
||||
|
||||
Suggested-by: Nick Xie <nick@khadas.com>
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
.../amlogic/meson-gxl-s905x-khadas-vim.dts | 50 +++++++++++++++++++
|
||||
1 file changed, 50 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
index 440bc23c7342..2c198c4212b2 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
@@ -6,6 +6,7 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/input/input.h>
|
||||
+#include <dt-bindings/thermal/thermal.h>
|
||||
|
||||
#include "meson-gxl-s905x-p212.dtsi"
|
||||
|
||||
@@ -63,6 +64,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ thermal-zones {
|
||||
+ cpu-thermal {
|
||||
+ polling-delay-passive = <250>; /* milliseconds */
|
||||
+ polling-delay = <1000>; /* milliseconds */
|
||||
+
|
||||
+ thermal-sensors = <&scpi_sensors 0>;
|
||||
+
|
||||
+ trips {
|
||||
+ cpu_alert0: cpu-alert0 {
|
||||
+ temperature = <70000>; /* millicelsius */
|
||||
+ hysteresis = <2000>; /* millicelsius */
|
||||
+ type = "active";
|
||||
+ };
|
||||
+
|
||||
+ cpu_alert1: cpu-alert1 {
|
||||
+ temperature = <80000>; /* millicelsius */
|
||||
+ hysteresis = <2000>; /* millicelsius */
|
||||
+ type = "passive";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ cooling-maps {
|
||||
+ map0 {
|
||||
+ trip = <&cpu_alert1>;
|
||||
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
|
||||
+ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
|
||||
+ <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
|
||||
+ <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -72,6 +106,22 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&cpu0 {
|
||||
+ #cooling-cells = <2>;
|
||||
+};
|
||||
+
|
||||
+&cpu1 {
|
||||
+ #cooling-cells = <2>;
|
||||
+};
|
||||
+
|
||||
+&cpu2 {
|
||||
+ #cooling-cells = <2>;
|
||||
+};
|
||||
+
|
||||
+&cpu3 {
|
||||
+ #cooling-cells = <2>;
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,46 +0,0 @@
|
||||
From 674d727336b1fe8e943fa1ccc58a743ea5265545 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Fri, 21 Feb 2020 04:49:36 +0000
|
||||
Subject: [PATCH 124/146] FROMLIST: arm64: dts: meson: khadas-vim3: move model
|
||||
to g12b-khadas-vim3 dtsi
|
||||
|
||||
The common meson-khadas-vim3.dtsi is now shared with VIM3L so move the
|
||||
VIM3 model namne to meson-g12b-khadas-vim3.dtsi.
|
||||
|
||||
meson-sm1-khadas-vim3l.dts contains the VIM3L model name.
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi | 2 ++
|
||||
arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi | 2 --
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
|
||||
index 554863429aa6..2b2d72c7746b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-g12b-khadas-vim3.dtsi
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <dt-bindings/sound/meson-g12a-tohdmitx.h>
|
||||
|
||||
/ {
|
||||
+ model = "Khadas VIM3";
|
||||
+
|
||||
vddcpu_a: regulator-vddcpu-a {
|
||||
/*
|
||||
* MP8756GD Regulator.
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
index 90815fa25ec6..0ef60c7151cb 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-khadas-vim3.dtsi
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <dt-bindings/gpio/meson-g12a-gpio.h>
|
||||
|
||||
/ {
|
||||
- model = "Khadas VIM3";
|
||||
-
|
||||
aliases {
|
||||
serial0 = &uart_AO;
|
||||
ethernet0 = ðmac;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -1,429 +0,0 @@
|
||||
From 09229328d9a37131993ac278e674d6ac8cca0c17 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Fri, 28 Feb 2020 19:16:35 +0000
|
||||
Subject: [PATCH 127/146] FROMLIST: arm64: dts: meson: add support for the
|
||||
Smartlabs SML-5442TW
|
||||
|
||||
The Smartlabs SML-5442TW is broadly similar to the P231 reference design
|
||||
but with the following differences:
|
||||
|
||||
- The Yellow and Blue LEDs are available but disabled
|
||||
- The Red and Green LEDs are used to signal off/on status
|
||||
- uart_AO can be accessed after opening the case; soldered pins exist
|
||||
- GPIOX_17 is forced high to enable the QCA9377 module (there are no
|
||||
device-tree bindings to do this at this time).
|
||||
|
||||
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/Makefile | 1 +
|
||||
.../dts/amlogic/meson-gxl-s905d-sml5442tw.dts | 386 ++++++++++++++++++
|
||||
2 files changed, 387 insertions(+)
|
||||
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
|
||||
index eef0045320f2..6cf8c4ac0390 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/Makefile
|
||||
+++ b/arch/arm64/boot/dts/amlogic/Makefile
|
||||
@@ -27,6 +27,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-phicomm-n1.dtb
|
||||
+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-sml5442tw.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb
|
||||
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts
|
||||
new file mode 100644
|
||||
index 000000000000..3ad53f794320
|
||||
--- /dev/null
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-sml5442tw.dts
|
||||
@@ -0,0 +1,386 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
+/*
|
||||
+ * Copyright (c) 2016 Endless Computers, Inc.
|
||||
+ * Author: Carlo Caione <carlo@endlessm.com>
|
||||
+ * Copyright (c) 2018 BayLibre, SAS
|
||||
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
+ */
|
||||
+
|
||||
+/dts-v1/;
|
||||
+
|
||||
+#include "meson-gxl-s905d.dtsi"
|
||||
+#include <dt-bindings/sound/meson-aiu.h>
|
||||
+
|
||||
+/ {
|
||||
+ compatible = "smartlabs,sml5442tw", "amlogic,s905d",
|
||||
+ "amlogic,meson-gxl";
|
||||
+ model = "SmartLabs SML-5442TW";
|
||||
+
|
||||
+ aliases {
|
||||
+ serial0 = &uart_AO;
|
||||
+ serial1 = &uart_A;
|
||||
+ ethernet0 = ðmac;
|
||||
+ };
|
||||
+
|
||||
+ chosen {
|
||||
+ stdout-path = "serial0:115200n8";
|
||||
+ };
|
||||
+
|
||||
+ memory@0 {
|
||||
+ device_type = "memory";
|
||||
+ reg = <0x0 0x0 0x0 0x80000000>;
|
||||
+ };
|
||||
+
|
||||
+ dio2133: analog-amplifier {
|
||||
+ compatible = "simple-audio-amplifier";
|
||||
+ sound-name-prefix = "AU2";
|
||||
+ VCC-supply = <&hdmi_5v>;
|
||||
+ enable-gpios = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>;
|
||||
+ };
|
||||
+
|
||||
+ spdif_dit: audio-codec-0 {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "linux,spdif-dit";
|
||||
+ status = "okay";
|
||||
+ sound-name-prefix = "DIT";
|
||||
+ };
|
||||
+
|
||||
+ leds {
|
||||
+ compatible = "gpio-leds";
|
||||
+
|
||||
+ yellow {
|
||||
+ label = "sml5442tw:yellow";
|
||||
+ gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>;
|
||||
+ default-state = "off";
|
||||
+ };
|
||||
+
|
||||
+ blue {
|
||||
+ label = "sml5442tw:blue";
|
||||
+ gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>;
|
||||
+ default-state = "off";
|
||||
+ };
|
||||
+
|
||||
+ green {
|
||||
+ label = "sml5442tw:green";
|
||||
+ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>;
|
||||
+ default-state = "on";
|
||||
+ };
|
||||
+
|
||||
+ red {
|
||||
+ label = "sml5442tw:red";
|
||||
+ gpios = <&gpio GPIODV_27 GPIO_ACTIVE_HIGH>;
|
||||
+ default-state = "off";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ hdmi_5v: regulator-hdmi-5v {
|
||||
+ compatible = "regulator-fixed";
|
||||
+
|
||||
+ regulator-name = "HDMI_5V";
|
||||
+ regulator-min-microvolt = <5000000>;
|
||||
+ regulator-max-microvolt = <5000000>;
|
||||
+
|
||||
+ gpio = <&gpio GPIOH_3 GPIO_ACTIVE_HIGH>;
|
||||
+ enable-active-high;
|
||||
+ regulator-always-on;
|
||||
+ };
|
||||
+
|
||||
+ vddio_ao18: regulator-vddio_ao18 {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "VDDIO_AO18";
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ };
|
||||
+
|
||||
+ vddio_boot: regulator-vddio_boot {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "VDDIO_BOOT";
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ };
|
||||
+
|
||||
+ vddao_3v3: regulator-vddao_3v3 {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "VDDAO_3V3";
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ };
|
||||
+
|
||||
+ vcc_3v3: regulator-vcc_3v3 {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "VCC_3V3";
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ };
|
||||
+
|
||||
+ emmc_pwrseq: emmc-pwrseq {
|
||||
+ compatible = "mmc-pwrseq-emmc";
|
||||
+ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
|
||||
+ };
|
||||
+
|
||||
+ wifi32k: wifi32k {
|
||||
+ compatible = "pwm-clock";
|
||||
+ #clock-cells = <0>;
|
||||
+ clock-frequency = <32768>;
|
||||
+ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */
|
||||
+ };
|
||||
+
|
||||
+ sdio_pwrseq: sdio-pwrseq {
|
||||
+ compatible = "mmc-pwrseq-simple";
|
||||
+ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
|
||||
+ clocks = <&wifi32k>;
|
||||
+ clock-names = "ext_clock";
|
||||
+ };
|
||||
+
|
||||
+ cvbs-connector {
|
||||
+ compatible = "composite-video-connector";
|
||||
+
|
||||
+ port {
|
||||
+ cvbs_connector_in: endpoint {
|
||||
+ remote-endpoint = <&cvbs_vdac_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ hdmi-connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_connector_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "amlogic,gx-sound-card";
|
||||
+ model = "GXL-S905D-SML5442TW";
|
||||
+ audio-aux-devs = <&dio2133>;
|
||||
+ audio-widgets = "Line", "Lineout";
|
||||
+ audio-routing = "AU2 INL", "ACODEC LOLP",
|
||||
+ "AU2 INR", "ACODEC LORP",
|
||||
+ "AU2 INL", "ACODEC LOLN",
|
||||
+ "AU2 INR", "ACODEC LORN",
|
||||
+ "Lineout", "AU2 OUTL",
|
||||
+ "Lineout", "AU2 OUTR";
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ dai-link-0 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-1 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_SPDIF_FIFO>;
|
||||
+ };
|
||||
+
|
||||
+ dai-link-2 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>;
|
||||
+ dai-format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_I2S>;
|
||||
+ };
|
||||
+
|
||||
+ codec-1 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_I2S>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-3 {
|
||||
+ sound-dai = <&aiu AIU_CPU CPU_SPDIF_ENCODER>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&spdif_dit>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-4 {
|
||||
+ sound-dai = <&aiu AIU_HDMI CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ dai-link-5 {
|
||||
+ sound-dai = <&aiu AIU_ACODEC CTRL_OUT>;
|
||||
+
|
||||
+ codec-0 {
|
||||
+ sound-dai = <&acodec>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&acodec {
|
||||
+ AVDD-supply = <&vddio_ao18>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&spdif_out_h_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+
|
||||
+};
|
||||
+
|
||||
+&cec_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&ao_cec_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-phandle = <&hdmi_tx>;
|
||||
+};
|
||||
+
|
||||
+&cvbs_vdac_port {
|
||||
+ cvbs_vdac_out: endpoint {
|
||||
+ remote-endpoint = <&cvbs_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+ðmac {
|
||||
+ status = "okay";
|
||||
+ phy-mode = "rmii";
|
||||
+ phy-handle = <&internal_phy>;
|
||||
+};
|
||||
+
|
||||
+/* This will enable the bluetooth module */
|
||||
+&gpio {
|
||||
+ bt-en {
|
||||
+ gpio-hog;
|
||||
+ gpios = <GPIOX_17 GPIO_ACTIVE_HIGH>;
|
||||
+ output-high;
|
||||
+ line-name = "bt-en";
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-supply = <&hdmi_5v>;
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx_tmds_port {
|
||||
+ hdmi_tx_tmds_out: endpoint {
|
||||
+ remote-endpoint = <&hdmi_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&i2c_A {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&i2c_a_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&internal_phy {
|
||||
+ pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&ir {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&remote_input_ao_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&pwm_ef {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&pwm_e_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ clocks = <&clkc CLKID_FCLK_DIV4>;
|
||||
+ clock-names = "clkin0";
|
||||
+};
|
||||
+
|
||||
+&saradc {
|
||||
+ status = "okay";
|
||||
+ vref-supply = <&vddio_ao18>;
|
||||
+};
|
||||
+
|
||||
+/* Wireless SDIO Module */
|
||||
+&sd_emmc_a {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&sdio_pins>;
|
||||
+ pinctrl-1 = <&sdio_clk_gate_pins>;
|
||||
+ pinctrl-names = "default", "clk-gate";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ bus-width = <4>;
|
||||
+ cap-sd-highspeed;
|
||||
+ max-frequency = <100000000>;
|
||||
+
|
||||
+ non-removable;
|
||||
+ disable-wp;
|
||||
+
|
||||
+ mmc-pwrseq = <&sdio_pwrseq>;
|
||||
+
|
||||
+ vmmc-supply = <&vddao_3v3>;
|
||||
+ vqmmc-supply = <&vddio_boot>;
|
||||
+};
|
||||
+
|
||||
+/* SD card */
|
||||
+&sd_emmc_b {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&sdcard_pins>;
|
||||
+ pinctrl-1 = <&sdcard_clk_gate_pins>;
|
||||
+ pinctrl-names = "default", "clk-gate";
|
||||
+
|
||||
+ bus-width = <4>;
|
||||
+ cap-sd-highspeed;
|
||||
+ max-frequency = <100000000>;
|
||||
+ disable-wp;
|
||||
+
|
||||
+ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
|
||||
+ cd-inverted;
|
||||
+
|
||||
+ vmmc-supply = <&vddao_3v3>;
|
||||
+ vqmmc-supply = <&vddio_boot>;
|
||||
+};
|
||||
+
|
||||
+/* eMMC */
|
||||
+&sd_emmc_c {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>;
|
||||
+ pinctrl-1 = <&emmc_clk_gate_pins>;
|
||||
+ pinctrl-names = "default", "clk-gate";
|
||||
+
|
||||
+ bus-width = <8>;
|
||||
+ cap-mmc-highspeed;
|
||||
+ max-frequency = <100000000>;
|
||||
+ non-removable;
|
||||
+ disable-wp;
|
||||
+ mmc-ddr-1_8v;
|
||||
+ mmc-hs200-1_8v;
|
||||
+
|
||||
+ mmc-pwrseq = <&emmc_pwrseq>;
|
||||
+ vmmc-supply = <&vcc_3v3>;
|
||||
+ vqmmc-supply = <&vddio_boot>;
|
||||
+};
|
||||
+
|
||||
+/* This is connected to the Bluetooth module: */
|
||||
+&uart_A {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ uart-has-rtscts;
|
||||
+};
|
||||
+
|
||||
+/* This UART is brought out to the debug header */
|
||||
+&uart_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&uart_ao_a_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
--
|
||||
2.17.1
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user