mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
osd: add osd sw_sync [1/1]
PD#SWPL-9736 Problem: osd fence crash when play AIV H264 video Solution: add osd sw_sync Verify: Verified with raven,w400 Change-Id: I309af0e3718221e2309460a990ef0badb9e8bd39 Signed-off-by: Pengcheng Chen <pengcheng.chen@amlogic.com>
This commit is contained in:
75
MAINTAINERS
75
MAINTAINERS
@@ -14892,12 +14892,71 @@ HARDKERNEL S922D odroidn2
|
||||
M: charles park <charles.park@hardkernel.com>
|
||||
F: Documentation/devicetree/binding/input/touchscreen/sx8650.txt
|
||||
|
||||
AMLOGIC LCD EXTERN DRIVER
|
||||
M: Shaochan Liu <shaochan.liu@amlogic.com>
|
||||
F: drivers/amlogic/media/vout/lcd/lcd_extern/i2c_CS602.c
|
||||
AMLOGIC GDC DRIVER
|
||||
M: Pengcheng Chen <pengcheng.chen@amlogic.com>
|
||||
F: drivers/amlogic/media/gdc/app/gdc_wq.c
|
||||
F: drivers/amlogic/media/gdc/app/gdc_wq.h
|
||||
|
||||
AMLOGIC SM1/G12A BL40 BOOTUP DRIVER
|
||||
M: shunzhou jiang <shunzhou.jiang@amlogic.com>
|
||||
F: drivers/amlogic/firmware/bl40_module.c
|
||||
F: drivers/amlogic/firmware/Makefile
|
||||
F: drivers/amlogic/firmware/Kconfig
|
||||
LAB126 PRIVACY
|
||||
M: LAB126
|
||||
F: drivers/misc/amz_priv*
|
||||
|
||||
LAB126 lifecycle and log
|
||||
M: LAB126
|
||||
F: drivers/staging/amazon/*
|
||||
|
||||
LAB126 tmp103
|
||||
M: LAB126
|
||||
F: drivers/hwmon/tmp103.c
|
||||
|
||||
LAB126 RAVEN DTS
|
||||
M: Yong Yu <yonyu@lab126.com>
|
||||
F: arch/arm64/boot/dts/amlogic/raven.dts
|
||||
F: arch/arm64/boot/dts/amlogic/raven_proto.dts
|
||||
F: Documentation/devicetree/bindings/iio/light/tsl2540.txt
|
||||
|
||||
LAB126 RAVEN DEFCONFIG
|
||||
M: Yong Yu <yonyu@lab126.com>
|
||||
F: arch/arm64/configs/raven_defconfig
|
||||
F: arch/arm64/configs/raven_debug_defconfig
|
||||
|
||||
LAB126 RAVEN THERMISTOR
|
||||
M: Kevin Ow <krow@amazon.com>
|
||||
F: Documentation/devicetree/bindings/thermal/ntc-bts-thermistor.txt
|
||||
F: drivers/amlogic/iio/adc/saradc_ntc_bts.c
|
||||
F: drivers/amlogic/iio/adc/Makefile
|
||||
F: drivers/amlogic/iio/adc/Kconfig
|
||||
|
||||
LAB126 RAVEN VIRTUAL THERMAL SENSOR
|
||||
M: Kevin Ow <krow@amazon.com>
|
||||
F: arch/arm64/boot/dts/amlogic/raven_thermal_zones.dtsi
|
||||
F: Documentation/devicetree/bindings/thermal/virtual_sensor_thermal.txt
|
||||
F: drivers/thermal/Kconfig
|
||||
F: drivers/thermal/Makefile
|
||||
F: drivers/thermal/trip_step_wise.c
|
||||
F: drivers/thermal/virtual_sensor_thermal.c
|
||||
F: include/linux/virtual_sensor_thermal.h
|
||||
|
||||
LAB126 RAVEN WIFI_COOLING
|
||||
M: Kevin Ow <krow@amazon.com>
|
||||
F: Documentation/devicetree/bindings/thermal/wifi-temp-sensor.txt
|
||||
F: drivers/thermal/wifi_cooling.c
|
||||
F: drivers/amlogic/thermal/aml_thermal_cooling.c
|
||||
F: drivers/amlogic/thermal/aml_thermal_hw.c
|
||||
F: include/linux/amlogic/aml_thermal_cooling.h
|
||||
F: include/linux/amlogic/aml_thermal_hw.h
|
||||
|
||||
THIRD PARTY AUDIO CODEC TLV320DAC3203
|
||||
M: Xing Fang <xing.fang@amlogic.com>
|
||||
F: sound/soc/codecs/tlv320dac3203.c
|
||||
F: sound/soc/codecs/tlv320dac3203.h
|
||||
|
||||
LAB126 PERFORMANCE BOOST DRIVER
|
||||
M: Yong Yu <yonyu@lab126.com>
|
||||
F: drivers/amlogic/cpufreq/cpufreq-boost.c
|
||||
F: include/linux/cpufreq-boost.h
|
||||
|
||||
ADD OSD SW_SYNC DRIVER
|
||||
M: Pengcheng Chen <pengcheng.chen@amlogic.com>
|
||||
F: drivers/amlogic/media/osd/osd_sw_sync.c
|
||||
F: drivers/amlogic/media/osd/osd_sw_sync.h
|
||||
|
||||
@@ -2,7 +2,7 @@ obj-$(CONFIG_AMLOGIC_MEDIA_FB) += fb.o
|
||||
fb-objs = osd_hw.o osd_fb.o osd_debug.o osd_backup.o osd_logo.o osd_io.o
|
||||
fb-objs += osd_antiflicker.o osd_clone.o
|
||||
fb-objs += osd_drm.o
|
||||
fb-objs += osd_rdma.o
|
||||
fb-objs += osd_rdma.o osd_sw_sync.o
|
||||
|
||||
obj-$(CONFIG_INSTABOOT) += osd_progressbar.o
|
||||
|
||||
|
||||
@@ -36,9 +36,6 @@
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
/* Android Headers */
|
||||
|
||||
/* Amlogic sync headers */
|
||||
#include <linux/amlogic/aml_sync_api.h>
|
||||
|
||||
/* Amlogic Headers */
|
||||
#include <linux/amlogic/media/vout/vinfo.h>
|
||||
#include <linux/amlogic/media/vout/vout_notify.h>
|
||||
@@ -74,6 +71,7 @@
|
||||
#include "osd_hw.h"
|
||||
#include "osd_hw_def.h"
|
||||
#include "osd_fb.h"
|
||||
#include "osd_sw_sync.h"
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_VSYNC_FIQ_ENABLE
|
||||
#define FIQ_VSYNC
|
||||
|
||||
298
drivers/amlogic/media/osd/osd_sw_sync.c
Normal file
298
drivers/amlogic/media/osd/osd_sw_sync.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* drivers/amlogic/media/osd/osd_sw_sync.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sync_file.h>
|
||||
|
||||
#include "osd_sw_sync.h"
|
||||
|
||||
static const struct fence_ops timeline_fence_ops;
|
||||
static inline struct sync_pt *fence_to_sync_pt(struct fence *fence)
|
||||
{
|
||||
if (fence->ops != &timeline_fence_ops)
|
||||
return NULL;
|
||||
return container_of(fence, struct sync_pt, base);
|
||||
}
|
||||
|
||||
/**
|
||||
* sync_timeline_create() - creates a sync object
|
||||
* @name: sync_timeline name
|
||||
*
|
||||
* Creates a new sync_timeline. Returns the sync_timeline object or NULL in
|
||||
* case of error.
|
||||
*/
|
||||
static struct sync_timeline *sync_timeline_create(const char *name)
|
||||
{
|
||||
struct sync_timeline *obj;
|
||||
|
||||
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
kref_init(&obj->kref);
|
||||
obj->context = fence_context_alloc(1);
|
||||
strlcpy(obj->name, name, sizeof(obj->name));
|
||||
INIT_LIST_HEAD(&obj->active_list_head);
|
||||
INIT_LIST_HEAD(&obj->pt_list);
|
||||
spin_lock_init(&obj->lock);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void sync_timeline_free(struct kref *kref)
|
||||
{
|
||||
struct sync_timeline *obj =
|
||||
container_of(kref, struct sync_timeline, kref);
|
||||
|
||||
kfree(obj);
|
||||
}
|
||||
|
||||
static void sync_timeline_get(struct sync_timeline *obj)
|
||||
{
|
||||
kref_get(&obj->kref);
|
||||
}
|
||||
|
||||
static void sync_timeline_put(struct sync_timeline *obj)
|
||||
{
|
||||
kref_put(&obj->kref, sync_timeline_free);
|
||||
}
|
||||
|
||||
static const char *timeline_fence_get_driver_name(struct fence *fence)
|
||||
{
|
||||
return "sw_sync";
|
||||
}
|
||||
|
||||
static const char *timeline_fence_get_timeline_name(struct fence *fence)
|
||||
{
|
||||
struct sync_timeline *parent = fence_parent(fence);
|
||||
|
||||
return parent->name;
|
||||
}
|
||||
|
||||
static void timeline_fence_release(struct fence *fence)
|
||||
{
|
||||
struct sync_pt *pt = fence_to_sync_pt(fence);
|
||||
struct sync_timeline *parent = fence_parent(fence);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(fence->lock, flags);
|
||||
list_del(&pt->link);
|
||||
if (!list_empty(&pt->active_list))
|
||||
list_del(&pt->active_list);
|
||||
spin_unlock_irqrestore(fence->lock, flags);
|
||||
sync_timeline_put(parent);
|
||||
fence_free(fence);
|
||||
}
|
||||
|
||||
static bool timeline_fence_signaled(struct fence *fence)
|
||||
{
|
||||
struct sync_timeline *parent = fence_parent(fence);
|
||||
|
||||
return !__fence_is_later(fence->seqno, parent->value);
|
||||
}
|
||||
|
||||
static bool timeline_fence_enable_signaling(struct fence *fence)
|
||||
{
|
||||
struct sync_pt *pt = container_of(fence, struct sync_pt, base);
|
||||
struct sync_timeline *parent = fence_parent(fence);
|
||||
|
||||
if (timeline_fence_signaled(fence))
|
||||
return false;
|
||||
|
||||
list_add_tail(&pt->active_list, &parent->active_list_head);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void timeline_fence_disable_signaling(struct fence *fence)
|
||||
{
|
||||
struct sync_pt *pt = container_of(fence, struct sync_pt, base);
|
||||
|
||||
list_del_init(&pt->active_list);
|
||||
}
|
||||
|
||||
static void timeline_fence_value_str(struct fence *fence,
|
||||
char *str, int size)
|
||||
{
|
||||
snprintf(str, size, "%d", fence->seqno);
|
||||
}
|
||||
|
||||
static void timeline_fence_timeline_value_str(struct fence *fence,
|
||||
char *str, int size)
|
||||
{
|
||||
struct sync_timeline *parent = fence_parent(fence);
|
||||
|
||||
snprintf(str, size, "%d", parent->value);
|
||||
}
|
||||
|
||||
static const struct fence_ops timeline_fence_ops = {
|
||||
.get_driver_name = timeline_fence_get_driver_name,
|
||||
.get_timeline_name = timeline_fence_get_timeline_name,
|
||||
.enable_signaling = timeline_fence_enable_signaling,
|
||||
.disable_signaling = timeline_fence_disable_signaling,
|
||||
.signaled = timeline_fence_signaled,
|
||||
.wait = fence_default_wait,
|
||||
.release = timeline_fence_release,
|
||||
.fence_value_str = timeline_fence_value_str,
|
||||
.timeline_value_str = timeline_fence_timeline_value_str,
|
||||
};
|
||||
|
||||
/**
|
||||
* sync_timeline_signal() - signal a status change on a sync_timeline
|
||||
* @obj: sync_timeline to signal
|
||||
* @inc: num to increment on timeline->value
|
||||
*
|
||||
* A sync implementation should call this any time one of it's fences
|
||||
* has signaled or has an error condition.
|
||||
*/
|
||||
static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc)
|
||||
{
|
||||
struct sync_pt *pt, *next;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&obj->lock, flags);
|
||||
obj->value += inc;
|
||||
list_for_each_entry_safe(pt, next, &obj->active_list_head,
|
||||
active_list) {
|
||||
if (fence_is_signaled_locked(&pt->base))
|
||||
list_del_init(&pt->active_list);
|
||||
}
|
||||
spin_unlock_irqrestore(&obj->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* sync_pt_create() - creates a sync pt
|
||||
* @parent: fence's parent sync_timeline
|
||||
* @inc: value of the fence
|
||||
*
|
||||
* Creates a new sync_pt as a child of @parent. @size bytes will be
|
||||
* allocated allowing for implementation specific data to be kept after
|
||||
* the generic sync_timeline struct. Returns the sync_pt object or
|
||||
* NULL in case of error.
|
||||
*/
|
||||
static struct sync_pt *sync_pt_create(struct sync_timeline *obj,
|
||||
unsigned int value)
|
||||
{
|
||||
struct sync_pt *pt;
|
||||
unsigned long flags;
|
||||
|
||||
pt = kzalloc(sizeof(*pt), GFP_KERNEL);
|
||||
if (!pt)
|
||||
return NULL;
|
||||
spin_lock_irqsave(&obj->lock, flags);
|
||||
sync_timeline_get(obj);
|
||||
fence_init(&pt->base, &timeline_fence_ops, &obj->lock,
|
||||
obj->context, value);
|
||||
list_add_tail(&pt->link, &obj->pt_list);
|
||||
INIT_LIST_HEAD(&pt->active_list);
|
||||
spin_unlock_irqrestore(&obj->lock, flags);
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
static void sync_pt_free(struct sync_timeline *obj,
|
||||
struct sync_pt *pt)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&obj->lock, flags);
|
||||
list_del(&pt->link);
|
||||
sync_timeline_put(obj);
|
||||
spin_unlock_irqrestore(&obj->lock, flags);
|
||||
kfree(pt);
|
||||
pt = NULL;
|
||||
}
|
||||
|
||||
void *aml_sync_create_timeline(const char *tname)
|
||||
{
|
||||
struct sync_timeline *timeline;
|
||||
|
||||
timeline = sync_timeline_create(tname);
|
||||
return (void *)timeline;
|
||||
}
|
||||
|
||||
int aml_sync_create_fence(void *timeline, unsigned int value)
|
||||
{
|
||||
struct sync_timeline *tl = (struct sync_timeline *)timeline;
|
||||
int fd;
|
||||
int err;
|
||||
struct sync_pt *pt;
|
||||
struct sync_file *sync_file;
|
||||
|
||||
if (tl == NULL)
|
||||
return -EPERM;
|
||||
|
||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
pt = sync_pt_create(tl, value);
|
||||
if (!pt) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sync_file = sync_file_create(&pt->base);
|
||||
fence_put(&pt->base);
|
||||
if (!sync_file) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fd_install(fd, sync_file->file);
|
||||
return fd;
|
||||
|
||||
err:
|
||||
put_unused_fd(fd);
|
||||
if (pt)
|
||||
sync_pt_free(tl, pt);
|
||||
return err;
|
||||
}
|
||||
|
||||
void aml_sync_inc_timeline(void *timeline, unsigned int value)
|
||||
{
|
||||
struct sync_timeline *tl = (struct sync_timeline *)timeline;
|
||||
|
||||
if (tl == NULL)
|
||||
return;
|
||||
while (value > INT_MAX) {
|
||||
sync_timeline_signal(tl, INT_MAX);
|
||||
value -= INT_MAX;
|
||||
}
|
||||
|
||||
sync_timeline_signal(tl, value);
|
||||
}
|
||||
|
||||
struct fence *aml_sync_get_fence(int syncfile_fd)
|
||||
{
|
||||
return sync_file_get_fence(syncfile_fd);
|
||||
}
|
||||
|
||||
int aml_sync_wait_fence(struct fence *fence, long timeout)
|
||||
{
|
||||
long ret;
|
||||
|
||||
ret = fence_wait_timeout(fence, false, timeout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void aml_sync_put_fence(struct fence *fence)
|
||||
{
|
||||
fence_put(fence);
|
||||
}
|
||||
60
drivers/amlogic/media/osd/osd_sw_sync.h
Normal file
60
drivers/amlogic/media/osd/osd_sw_sync.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* drivers/amlogic/media/osd/osd_sw_sync.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _OSD_SW_SYNC_H
|
||||
#define _OSD_SW_SYNC_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fence.h>
|
||||
|
||||
#include <linux/sync_file.h>
|
||||
#include <uapi/linux/sync_file.h>
|
||||
|
||||
|
||||
struct sync_timeline {
|
||||
struct kref kref;
|
||||
char name[32];
|
||||
|
||||
/* protected by lock */
|
||||
u64 context;
|
||||
int value;
|
||||
|
||||
struct list_head active_list_head;
|
||||
struct list_head pt_list;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static inline struct sync_timeline *fence_parent(struct fence *fence)
|
||||
{
|
||||
return container_of(fence->lock, struct sync_timeline, lock);
|
||||
}
|
||||
|
||||
struct sync_pt {
|
||||
struct fence base;
|
||||
struct list_head link;
|
||||
struct list_head active_list;
|
||||
};
|
||||
|
||||
void *aml_sync_create_timeline(const char *tname);
|
||||
int aml_sync_create_fence(void *timeline, unsigned int value);
|
||||
void aml_sync_inc_timeline(void *timeline, unsigned int value);
|
||||
struct fence *aml_sync_get_fence(int syncfile_fd);
|
||||
int aml_sync_wait_fence(struct fence *fence, long timeout);
|
||||
void aml_sync_put_fence(struct fence *fence);
|
||||
#endif /* _OSD_SW_SYNC_H */
|
||||
Reference in New Issue
Block a user