Merge tag 'drm-misc-next-2019-10-09-2' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 5.5:

UAPI Changes:
-Colorspace: Expose different prop values for DP vs. HDMI (Gwan-gyeong Mun)
-fourcc: Add DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED (Raymond)
-not_actually: s/ENOTSUPP/EOPNOTSUPP/ in drm_edid and drm_mipi_dbi. This should
    not reach userspace, but adding here to specifically call that out (Daniel)
-i810: Prevent underflow in dispatch ioctls (Dan)
-komeda: Add ACLK sysfs attribute (Mihail)
-v3d: Allow userspace to clean up after render jobs (Iago)

Cross-subsystem Changes:
-MAINTAINERS:
 -Add Alyssa & Steven as panfrost reviewers (Rob)
 -Add Jernej as DE2 reviewer (Maxime)
 -Add Chen-Yu as Allwinner maintainer (Maxime)
-staging: Make some stack arrays static const (Colin)

Core Changes:
-ttm: Allow drivers to specify their vma manager (to use gem mgr) (Gerd)
-docs: Various fixes in connector/encoder/bridge docs (Daniel, Lyude, Laurent)
-connector: Allow more than 3 possible encoders for a connector (José)
-dp_cec: Allow a connector to be associated with a cec device (Dariusz)
-various: Fix some compile/sparse warnings (Ville)
-mm: Ensure mm node removals are properly serialised (Chris)
-panel: Specify the type of panel for drm_panels for later use (Laurent)
-panel: Use drm_panel_init to init device and funcs (Laurent)
-mst: Refactors and cleanups in anticipation of suspend/resume support (Lyude)
-vram:
 -Add lazy unmapping for gem bo's (Thomas)
 -Unify and rationalize vram mm and gem vram (Thomas)
 -Expose vmap and vunmap for gem vram objects (Thomas)
 -Allow objects to be pinned at the top of vram to avoid fragmentation (Thomas)

Driver Changes:
-various: Include drm_bridge.h instead of relying on drm_crtc.h (Boris)
-ast/mgag200: Refactor show_cursor(), move cursor to top of video mem (Thomas)
-komeda:
 -Add error event printing (behind CONFIG) and reg dump support (Lowry)
 -Add suspend/resume support (Lowry)
 -Workaround D71 shadow registers not flushing on disable (Lowry)
-meson: Add suspend/resume support (Neil)
-omap: Miscellaneous refactors and improvements (Tomi/Jyri)
-panfrost/shmem: Silence lockdep by using mutex_trylock (Rob)
-panfrost: Miscellaneous small fixes (Rob/Steven)
-sti: Fix warnings (Benjamin/Linus)
-sun4i:
 -Add vcc-dsi regulator to sun6i_mipi_dsi (Jagan)
 -A few patches to figure out the DRQ/start delay calc on dsi (Jagan/Icenowy)
-virtio:
 -Add module param to switch resource reuse workaround on/off (Gerd)
 -Avoid calling vmexit while holding spinlock (Gerd)
 -Use gem shmem helpers instead of ttm (Gerd)
 -Accommodate command buffer allocations too big for cma (David)

Cc: Rob Herring <robh@kernel.org>
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Gwan-gyeong Mun <gwan-gyeong.mun@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Lyude Paul <lyude@redhat.com>
Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Dariusz Marcinkiewicz <darekm@google.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Raymond Smith <raymond.smith@arm.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Mihail Atanassov <Mihail.Atanassov@arm.com>
Cc: Lowry Li <Lowry.Li@arm.com>
Cc: Neil Armstrong <narmstrong@baylibre.com>
Cc: Jyri Sarha <jsarha@ti.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Benjamin Gaignard <benjamin.gaignard@st.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Jagan Teki <jagan@amarulasolutions.com>
Cc: Icenowy Zheng <icenowy@aosc.io>
Cc: Iago Toral Quiroga <itoral@igalia.com>
Cc: David Riley <davidriley@chromium.org>
Signed-off-by: Dave Airlie <airlied@redhat.com>

# gpg: Signature made Thu 10 Oct 2019 01:00:47 AM AEST
# gpg:                using RSA key 732C002572DCAF79
# gpg: Can't check signature: public key not found

# Conflicts:
#	drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
#	drivers/gpu/drm/i915/i915_drv.c
#	drivers/gpu/drm/i915/i915_gem.c
#	drivers/gpu/drm/i915/i915_gem_gtt.c
#	drivers/gpu/drm/i915/i915_vma.c
From: Sean Paul <sean@poorly.run>
Link: https://patchwork.freedesktop.org/patch/msgid/20191009150825.GA227673@art_vandelay
This commit is contained in:
Dave Airlie
2019-10-11 09:30:52 +10:00
299 changed files with 4661 additions and 2998 deletions

View File

@@ -12,3 +12,9 @@ config DRM_KOMEDA
Processor driver. It supports the D71 variants of the hardware.
If compiled as a module it will be called komeda.
config DRM_KOMEDA_ERROR_PRINT
bool "Enable komeda error print"
depends on DRM_KOMEDA
help
Choose this option to enable error printing.

View File

@@ -22,4 +22,6 @@ komeda-y += \
d71/d71_dev.o \
d71/d71_component.o
komeda-$(CONFIG_DRM_KOMEDA_ERROR_PRINT) += komeda_event.o
obj-$(CONFIG_DRM_KOMEDA) += komeda.o

View File

@@ -1218,6 +1218,90 @@ int d71_probe_block(struct d71_dev *d71,
return err;
}
static void d71_gcu_dump(struct d71_dev *d71, struct seq_file *sf)
{
u32 v[5];
seq_puts(sf, "\n------ GCU ------\n");
get_values_from_reg(d71->gcu_addr, 0, 3, v);
seq_printf(sf, "GLB_ARCH_ID:\t\t0x%X\n", v[0]);
seq_printf(sf, "GLB_CORE_ID:\t\t0x%X\n", v[1]);
seq_printf(sf, "GLB_CORE_INFO:\t\t0x%X\n", v[2]);
get_values_from_reg(d71->gcu_addr, 0x10, 1, v);
seq_printf(sf, "GLB_IRQ_STATUS:\t\t0x%X\n", v[0]);
get_values_from_reg(d71->gcu_addr, 0xA0, 5, v);
seq_printf(sf, "GCU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
seq_printf(sf, "GCU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
seq_printf(sf, "GCU_IRQ_MASK:\t\t0x%X\n", v[2]);
seq_printf(sf, "GCU_IRQ_STATUS:\t\t0x%X\n", v[3]);
seq_printf(sf, "GCU_STATUS:\t\t0x%X\n", v[4]);
get_values_from_reg(d71->gcu_addr, 0xD0, 3, v);
seq_printf(sf, "GCU_CONTROL:\t\t0x%X\n", v[0]);
seq_printf(sf, "GCU_CONFIG_VALID0:\t0x%X\n", v[1]);
seq_printf(sf, "GCU_CONFIG_VALID1:\t0x%X\n", v[2]);
}
static void d71_lpu_dump(struct d71_pipeline *pipe, struct seq_file *sf)
{
u32 v[6];
seq_printf(sf, "\n------ LPU%d ------\n", pipe->base.id);
dump_block_header(sf, pipe->lpu_addr);
get_values_from_reg(pipe->lpu_addr, 0xA0, 6, v);
seq_printf(sf, "LPU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
seq_printf(sf, "LPU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
seq_printf(sf, "LPU_IRQ_MASK:\t\t0x%X\n", v[2]);
seq_printf(sf, "LPU_IRQ_STATUS:\t\t0x%X\n", v[3]);
seq_printf(sf, "LPU_STATUS:\t\t0x%X\n", v[4]);
seq_printf(sf, "LPU_TBU_STATUS:\t\t0x%X\n", v[5]);
get_values_from_reg(pipe->lpu_addr, 0xC0, 1, v);
seq_printf(sf, "LPU_INFO:\t\t0x%X\n", v[0]);
get_values_from_reg(pipe->lpu_addr, 0xD0, 3, v);
seq_printf(sf, "LPU_RAXI_CONTROL:\t0x%X\n", v[0]);
seq_printf(sf, "LPU_WAXI_CONTROL:\t0x%X\n", v[1]);
seq_printf(sf, "LPU_TBU_CONTROL:\t0x%X\n", v[2]);
}
static void d71_dou_dump(struct d71_pipeline *pipe, struct seq_file *sf)
{
u32 v[5];
seq_printf(sf, "\n------ DOU%d ------\n", pipe->base.id);
dump_block_header(sf, pipe->dou_addr);
get_values_from_reg(pipe->dou_addr, 0xA0, 5, v);
seq_printf(sf, "DOU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
seq_printf(sf, "DOU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
seq_printf(sf, "DOU_IRQ_MASK:\t\t0x%X\n", v[2]);
seq_printf(sf, "DOU_IRQ_STATUS:\t\t0x%X\n", v[3]);
seq_printf(sf, "DOU_STATUS:\t\t0x%X\n", v[4]);
}
static void d71_pipeline_dump(struct komeda_pipeline *pipe, struct seq_file *sf)
{
struct d71_pipeline *d71_pipe = to_d71_pipeline(pipe);
d71_lpu_dump(d71_pipe, sf);
d71_dou_dump(d71_pipe, sf);
}
const struct komeda_pipeline_funcs d71_pipeline_funcs = {
.downscaling_clk_check = d71_downscaling_clk_check,
.downscaling_clk_check = d71_downscaling_clk_check,
.dump_register = d71_pipeline_dump,
};
void d71_dump(struct komeda_dev *mdev, struct seq_file *sf)
{
struct d71_dev *d71 = mdev->chip_data;
d71_gcu_dump(d71, sf);
}

View File

@@ -195,7 +195,7 @@ d71_irq_handler(struct komeda_dev *mdev, struct komeda_events *evts)
if (gcu_status & GLB_IRQ_STATUS_PIPE1)
evts->pipes[1] |= get_pipeline_event(d71->pipes[1], gcu_status);
return gcu_status ? IRQ_HANDLED : IRQ_NONE;
return IRQ_RETVAL(gcu_status);
}
#define ENABLED_GCU_IRQS (GCU_IRQ_CVAL0 | GCU_IRQ_CVAL1 | \
@@ -395,6 +395,22 @@ static int d71_enum_resources(struct komeda_dev *mdev)
err = PTR_ERR(pipe);
goto err_cleanup;
}
/* D71 HW doesn't update shadow registers when display output
* is turning off, so when we disable all pipeline components
* together with display output disable by one flush or one
* operation, the disable operation updated registers will not
* be flush to or valid in HW, which may leads problem.
* To workaround this problem, introduce a two phase disable.
* Phase1: Disabling components with display is on to make sure
* the disable can be flushed to HW.
* Phase2: Only turn-off display output.
*/
value = KOMEDA_PIPELINE_IMPROCS |
BIT(KOMEDA_COMPONENT_TIMING_CTRLR);
pipe->standalone_disabled_comps = value;
d71->pipes[i] = to_d71_pipeline(pipe);
}
@@ -561,17 +577,18 @@ static int d71_disconnect_iommu(struct komeda_dev *mdev)
}
static const struct komeda_dev_funcs d71_chip_funcs = {
.init_format_table = d71_init_fmt_tbl,
.enum_resources = d71_enum_resources,
.cleanup = d71_cleanup,
.irq_handler = d71_irq_handler,
.enable_irq = d71_enable_irq,
.disable_irq = d71_disable_irq,
.on_off_vblank = d71_on_off_vblank,
.change_opmode = d71_change_opmode,
.flush = d71_flush,
.connect_iommu = d71_connect_iommu,
.disconnect_iommu = d71_disconnect_iommu,
.init_format_table = d71_init_fmt_tbl,
.enum_resources = d71_enum_resources,
.cleanup = d71_cleanup,
.irq_handler = d71_irq_handler,
.enable_irq = d71_enable_irq,
.disable_irq = d71_disable_irq,
.on_off_vblank = d71_on_off_vblank,
.change_opmode = d71_change_opmode,
.flush = d71_flush,
.connect_iommu = d71_connect_iommu,
.disconnect_iommu = d71_disconnect_iommu,
.dump_register = d71_dump,
};
const struct komeda_dev_funcs *

View File

@@ -49,4 +49,6 @@ int d71_probe_block(struct d71_dev *d71,
struct block_header *blk, u32 __iomem *reg);
void d71_read_block_header(u32 __iomem *reg, struct block_header *blk);
void d71_dump(struct komeda_dev *mdev, struct seq_file *sf);
#endif /* !_D71_DEV_H_ */

View File

@@ -5,7 +5,6 @@
*
*/
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <drm/drm_atomic.h>
@@ -250,23 +249,57 @@ komeda_crtc_atomic_enable(struct drm_crtc *crtc,
{
komeda_crtc_prepare(to_kcrtc(crtc));
drm_crtc_vblank_on(crtc);
WARN_ON(drm_crtc_vblank_get(crtc));
komeda_crtc_do_flush(crtc, old);
}
static void
komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc,
struct completion *input_flip_done)
{
struct drm_device *drm = kcrtc->base.dev;
struct komeda_dev *mdev = kcrtc->master->mdev;
struct completion *flip_done;
struct completion temp;
int timeout;
/* if caller doesn't send a flip_done, use a private flip_done */
if (input_flip_done) {
flip_done = input_flip_done;
} else {
init_completion(&temp);
kcrtc->disable_done = &temp;
flip_done = &temp;
}
mdev->funcs->flush(mdev, kcrtc->master->id, 0);
/* wait the flip take affect.*/
timeout = wait_for_completion_timeout(flip_done, HZ);
if (timeout == 0) {
DRM_ERROR("wait pipe%d flip done timeout\n", kcrtc->master->id);
if (!input_flip_done) {
unsigned long flags;
spin_lock_irqsave(&drm->event_lock, flags);
kcrtc->disable_done = NULL;
spin_unlock_irqrestore(&drm->event_lock, flags);
}
}
}
static void
komeda_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old)
{
struct komeda_crtc *kcrtc = to_kcrtc(crtc);
struct komeda_crtc_state *old_st = to_kcrtc_st(old);
struct komeda_dev *mdev = crtc->dev->dev_private;
struct komeda_pipeline *master = kcrtc->master;
struct komeda_pipeline *slave = kcrtc->slave;
struct completion *disable_done = &crtc->state->commit->flip_done;
struct completion temp;
int timeout;
bool needs_phase2 = false;
DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x.\n",
DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n",
drm_crtc_index(crtc),
old_st->active_pipes, old_st->affected_pipes);
@@ -274,7 +307,7 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc,
komeda_pipeline_disable(slave, old->state);
if (has_bit(master->id, old_st->active_pipes))
komeda_pipeline_disable(master, old->state);
needs_phase2 = komeda_pipeline_disable(master, old->state);
/* crtc_disable has two scenarios according to the state->active switch.
* 1. active -> inactive
@@ -293,32 +326,23 @@ komeda_crtc_atomic_disable(struct drm_crtc *crtc,
* That's also the reason why skip modeset commit in
* komeda_crtc_atomic_flush()
*/
if (crtc->state->active) {
struct komeda_pipeline_state *pipe_st;
/* clear the old active_comps to zero */
pipe_st = komeda_pipeline_get_old_state(master, old->state);
pipe_st->active_comps = 0;
disable_done = (needs_phase2 || crtc->state->active) ?
NULL : &crtc->state->commit->flip_done;
init_completion(&temp);
kcrtc->disable_done = &temp;
disable_done = &temp;
}
mdev->funcs->flush(mdev, master->id, 0);
/* wait the disable take affect.*/
timeout = wait_for_completion_timeout(disable_done, HZ);
if (timeout == 0) {
DRM_ERROR("disable pipeline%d timeout.\n", kcrtc->master->id);
if (crtc->state->active) {
unsigned long flags;
spin_lock_irqsave(&crtc->dev->event_lock, flags);
kcrtc->disable_done = NULL;
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
}
/* wait phase 1 disable done */
komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done);
/* phase 2 */
if (needs_phase2) {
komeda_pipeline_disable(kcrtc->master, old->state);
disable_done = crtc->state->active ?
NULL : &crtc->state->commit->flip_done;
komeda_crtc_flush_and_wait_for_flip_done(kcrtc, disable_done);
}
drm_crtc_vblank_put(crtc);
drm_crtc_vblank_off(crtc);
komeda_crtc_unprepare(kcrtc);
}

View File

@@ -25,6 +25,8 @@ static int komeda_register_show(struct seq_file *sf, void *x)
struct komeda_dev *mdev = sf->private;
int i;
seq_puts(sf, "\n====== Komeda register dump =========\n");
if (mdev->funcs->dump_register)
mdev->funcs->dump_register(mdev, sf);
@@ -91,9 +93,19 @@ config_id_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(config_id);
static ssize_t
aclk_hz_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct komeda_dev *mdev = dev_to_mdev(dev);
return snprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(mdev->aclk));
}
static DEVICE_ATTR_RO(aclk_hz);
static struct attribute *komeda_sysfs_entries[] = {
&dev_attr_core_id.attr,
&dev_attr_config_id.attr,
&dev_attr_aclk_hz.attr,
NULL,
};
@@ -216,7 +228,7 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
product->product_id,
MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
err = -ENODEV;
goto err_cleanup;
goto disable_clk;
}
DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
@@ -229,19 +241,19 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
err = mdev->funcs->enum_resources(mdev);
if (err) {
DRM_ERROR("enumerate display resource failed.\n");
goto err_cleanup;
goto disable_clk;
}
err = komeda_parse_dt(dev, mdev);
if (err) {
DRM_ERROR("parse device tree failed.\n");
goto err_cleanup;
goto disable_clk;
}
err = komeda_assemble_pipelines(mdev);
if (err) {
DRM_ERROR("assemble display pipelines failed.\n");
goto err_cleanup;
goto disable_clk;
}
dev->dma_parms = &mdev->dma_parms;
@@ -254,11 +266,14 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
if (mdev->iommu && mdev->funcs->connect_iommu) {
err = mdev->funcs->connect_iommu(mdev);
if (err) {
DRM_ERROR("connect iommu failed.\n");
mdev->iommu = NULL;
goto err_cleanup;
goto disable_clk;
}
}
clk_disable_unprepare(mdev->aclk);
err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
if (err) {
DRM_ERROR("create sysfs group failed.\n");
@@ -271,6 +286,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
return mdev;
disable_clk:
clk_disable_unprepare(mdev->aclk);
err_cleanup:
komeda_dev_destroy(mdev);
return ERR_PTR(err);
@@ -288,8 +305,12 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
debugfs_remove_recursive(mdev->debugfs_root);
#endif
if (mdev->aclk)
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->disconnect_iommu)
mdev->funcs->disconnect_iommu(mdev);
if (mdev->funcs->disconnect_iommu(mdev))
DRM_ERROR("disconnect iommu failed.\n");
mdev->iommu = NULL;
for (i = 0; i < mdev->n_pipelines; i++) {
@@ -317,3 +338,47 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
devm_kfree(dev, mdev);
}
int komeda_dev_resume(struct komeda_dev *mdev)
{
int ret = 0;
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->connect_iommu) {
ret = mdev->funcs->connect_iommu(mdev);
if (ret < 0) {
DRM_ERROR("connect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->enable_irq(mdev);
disable_clk:
clk_disable_unprepare(mdev->aclk);
return ret;
}
int komeda_dev_suspend(struct komeda_dev *mdev)
{
int ret = 0;
clk_prepare_enable(mdev->aclk);
if (mdev->iommu && mdev->funcs->disconnect_iommu) {
ret = mdev->funcs->disconnect_iommu(mdev);
if (ret < 0) {
DRM_ERROR("disconnect iommu failed.\n");
goto disable_clk;
}
}
ret = mdev->funcs->disable_irq(mdev);
disable_clk:
clk_disable_unprepare(mdev->aclk);
return ret;
}

View File

@@ -40,6 +40,17 @@
#define KOMEDA_ERR_TTNG BIT_ULL(30)
#define KOMEDA_ERR_TTF BIT_ULL(31)
#define KOMEDA_ERR_EVENTS \
(KOMEDA_EVENT_URUN | KOMEDA_EVENT_IBSY | KOMEDA_EVENT_OVR |\
KOMEDA_ERR_TETO | KOMEDA_ERR_TEMR | KOMEDA_ERR_TITR |\
KOMEDA_ERR_CPE | KOMEDA_ERR_CFGE | KOMEDA_ERR_AXIE |\
KOMEDA_ERR_ACE0 | KOMEDA_ERR_ACE1 | KOMEDA_ERR_ACE2 |\
KOMEDA_ERR_ACE3 | KOMEDA_ERR_DRIFTTO | KOMEDA_ERR_FRAMETO |\
KOMEDA_ERR_ZME | KOMEDA_ERR_MERR | KOMEDA_ERR_TCF |\
KOMEDA_ERR_TTNG | KOMEDA_ERR_TTF)
#define KOMEDA_WARN_EVENTS KOMEDA_ERR_CSCE
/* malidp device id */
enum {
MALI_D71 = 0,
@@ -207,4 +218,13 @@ void komeda_dev_destroy(struct komeda_dev *mdev);
struct komeda_dev *dev_to_mdev(struct device *dev);
#ifdef CONFIG_DRM_KOMEDA_ERROR_PRINT
void komeda_print_events(struct komeda_events *evts);
#else
static inline void komeda_print_events(struct komeda_events *evts) {}
#endif
int komeda_dev_resume(struct komeda_dev *mdev);
int komeda_dev_suspend(struct komeda_dev *mdev);
#endif /*_KOMEDA_DEV_H_*/

View File

@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/component.h>
#include <linux/pm_runtime.h>
#include <drm/drm_of.h>
#include "komeda_dev.h"
#include "komeda_kms.h"
@@ -136,13 +137,40 @@ static const struct of_device_id komeda_of_match[] = {
MODULE_DEVICE_TABLE(of, komeda_of_match);
static int __maybe_unused komeda_pm_suspend(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
int res;
res = drm_mode_config_helper_suspend(drm);
komeda_dev_suspend(mdrv->mdev);
return res;
}
static int __maybe_unused komeda_pm_resume(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);
struct drm_device *drm = &mdrv->kms->base;
komeda_dev_resume(mdrv->mdev);
return drm_mode_config_helper_resume(drm);
}
static const struct dev_pm_ops komeda_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume)
};
static struct platform_driver komeda_platform_driver = {
.probe = komeda_platform_probe,
.remove = komeda_platform_remove,
.driver = {
.name = "komeda",
.of_match_table = komeda_of_match,
.pm = NULL,
.pm = &komeda_pm_ops,
},
};

View File

@@ -0,0 +1,140 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
* Author: James.Qian.Wang <james.qian.wang@arm.com>
*
*/
#include <drm/drm_print.h>
#include "komeda_dev.h"
struct komeda_str {
char *str;
u32 sz;
u32 len;
};
/* return 0 on success, < 0 on no space.
*/
static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...)
{
va_list args;
int num, free_sz;
int err;
free_sz = str->sz - str->len - 1;
if (free_sz <= 0)
return -ENOSPC;
va_start(args, fmt);
num = vsnprintf(str->str + str->len, free_sz, fmt, args);
va_end(args);
if (num < free_sz) {
str->len += num;
err = 0;
} else {
str->len = str->sz - 1;
err = -ENOSPC;
}
return err;
}
static void evt_sprintf(struct komeda_str *str, u64 evt, const char *msg)
{
if (evt)
komeda_sprintf(str, msg);
}
static void evt_str(struct komeda_str *str, u64 events)
{
if (events == 0ULL) {
komeda_sprintf(str, "None");
return;
}
evt_sprintf(str, events & KOMEDA_EVENT_VSYNC, "VSYNC|");
evt_sprintf(str, events & KOMEDA_EVENT_FLIP, "FLIP|");
evt_sprintf(str, events & KOMEDA_EVENT_EOW, "EOW|");
evt_sprintf(str, events & KOMEDA_EVENT_MODE, "OP-MODE|");
evt_sprintf(str, events & KOMEDA_EVENT_URUN, "UNDERRUN|");
evt_sprintf(str, events & KOMEDA_EVENT_OVR, "OVERRUN|");
/* GLB error */
evt_sprintf(str, events & KOMEDA_ERR_MERR, "MERR|");
evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|");
/* DOU error */
evt_sprintf(str, events & KOMEDA_ERR_DRIFTTO, "DRIFTTO|");
evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|");
evt_sprintf(str, events & KOMEDA_ERR_TETO, "TETO|");
evt_sprintf(str, events & KOMEDA_ERR_CSCE, "CSCE|");
/* LPU errors or events */
evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|");
evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|");
evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|");
evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|");
evt_sprintf(str, events & KOMEDA_ERR_ACE2, "ACE2|");
evt_sprintf(str, events & KOMEDA_ERR_ACE3, "ACE3|");
/* LPU TBU errors*/
evt_sprintf(str, events & KOMEDA_ERR_TCF, "TCF|");
evt_sprintf(str, events & KOMEDA_ERR_TTNG, "TTNG|");
evt_sprintf(str, events & KOMEDA_ERR_TITR, "TITR|");
evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|");
evt_sprintf(str, events & KOMEDA_ERR_TTF, "TTF|");
/* CU errors*/
evt_sprintf(str, events & KOMEDA_ERR_CPE, "COPROC|");
evt_sprintf(str, events & KOMEDA_ERR_ZME, "ZME|");
evt_sprintf(str, events & KOMEDA_ERR_CFGE, "CFGE|");
evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|");
if (str->len > 0 && (str->str[str->len - 1] == '|')) {
str->str[str->len - 1] = 0;
str->len--;
}
}
static bool is_new_frame(struct komeda_events *a)
{
return (a->pipes[0] | a->pipes[1]) &
(KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW);
}
void komeda_print_events(struct komeda_events *evts)
{
u64 print_evts = KOMEDA_ERR_EVENTS;
static bool en_print = true;
/* reduce the same msg print, only print the first evt for one frame */
if (evts->global || is_new_frame(evts))
en_print = true;
if (!en_print)
return;
if ((evts->global | evts->pipes[0] | evts->pipes[1]) & print_evts) {
char msg[256];
struct komeda_str str;
str.str = msg;
str.sz = sizeof(msg);
str.len = 0;
komeda_sprintf(&str, "gcu: ");
evt_str(&str, evts->global);
komeda_sprintf(&str, ", pipes[0]: ");
evt_str(&str, evts->pipes[0]);
komeda_sprintf(&str, ", pipes[1]: ");
evt_str(&str, evts->pipes[1]);
DRM_ERROR("err detect: %s\n", msg);
en_print = false;
}
}

View File

@@ -48,6 +48,8 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
memset(&evts, 0, sizeof(evts));
status = mdev->funcs->irq_handler(mdev, &evts);
komeda_print_events(&evts);
/* Notify the crtc to handle the events */
for (i = 0; i < kms->n_crtcs; i++)
komeda_crtc_handle_event(&kms->crtcs[i], &evts);

View File

@@ -389,6 +389,18 @@ struct komeda_pipeline {
int id;
/** @avail_comps: available components mask of pipeline */
u32 avail_comps;
/**
* @standalone_disabled_comps:
*
* When disable the pipeline, some components can not be disabled
* together with others, but need a sparated and standalone disable.
* The standalone_disabled_comps are the components which need to be
* disabled standalone, and this concept also introduce concept of
* two phase.
* phase 1: for disabling the common components.
* phase 2: for disabling the standalong_disabled_comps.
*/
u32 standalone_disabled_comps;
/** @n_layers: the number of layer on @layers */
int n_layers;
/** @layers: the pipeline layers */
@@ -535,7 +547,7 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
struct komeda_pipeline_state *
komeda_pipeline_get_old_state(struct komeda_pipeline *pipe,
struct drm_atomic_state *state);
void komeda_pipeline_disable(struct komeda_pipeline *pipe,
bool komeda_pipeline_disable(struct komeda_pipeline *pipe,
struct drm_atomic_state *old_state);
void komeda_pipeline_update(struct komeda_pipeline *pipe,
struct drm_atomic_state *old_state);

View File

@@ -1218,7 +1218,17 @@ int komeda_release_unclaimed_resources(struct komeda_pipeline *pipe,
return 0;
}
void komeda_pipeline_disable(struct komeda_pipeline *pipe,
/* Since standalong disabled components must be disabled separately and in the
* last, So a complete disable operation may needs to call pipeline_disable
* twice (two phase disabling).
* Phase 1: disable the common components, flush it.
* Phase 2: disable the standalone disabled components, flush it.
*
* RETURNS:
* true: disable is not complete, needs a phase 2 disable.
* false: disable is complete.
*/
bool komeda_pipeline_disable(struct komeda_pipeline *pipe,
struct drm_atomic_state *old_state)
{
struct komeda_pipeline_state *old;
@@ -1228,9 +1238,14 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe,
old = komeda_pipeline_get_old_state(pipe, old_state);
disabling_comps = old->active_comps;
DRM_DEBUG_ATOMIC("PIPE%d: disabling_comps: 0x%x.\n",
pipe->id, disabling_comps);
disabling_comps = old->active_comps &
(~pipe->standalone_disabled_comps);
if (!disabling_comps)
disabling_comps = old->active_comps &
pipe->standalone_disabled_comps;
DRM_DEBUG_ATOMIC("PIPE%d: active_comps: 0x%x, disabling_comps: 0x%x.\n",
pipe->id, old->active_comps, disabling_comps);
dp_for_each_set_bit(id, disabling_comps) {
c = komeda_pipeline_get_component(pipe, id);
@@ -1248,6 +1263,13 @@ void komeda_pipeline_disable(struct komeda_pipeline *pipe,
c->funcs->disable(c);
}
/* Update the pipeline state, if there are components that are still
* active, return true for calling the phase 2 disable.
*/
old->active_comps &= ~disabling_comps;
return old->active_comps ? true : false;
}
void komeda_pipeline_update(struct komeda_pipeline *pipe,