1
0
Fork 0

drm/komeda: Add irq handling

1. Added irq_handler/irq_enable/irq_disable to komeda_dev_func, then the
   Komeda-CORE can control the HW irq via these chip function.
2. Install irq and register irq_handler to system by DRM, so once the IRQ
   coming, the handling sequence is:

   komeda_kms_irq_handler(int irq, void *data)
        /* step 1. call into the CHIP to recognize event */
	mdev->funcs->irq_handler(mdev, &evts);

	/* step 2. notify the crtc to handle the events */
	for (i = 0; i < kms->n_crtcs; i++)
		komeda_crtc_handle_event(&kms->crtcs[i], &evts);

v2:
- Move get IRQ number into this change.
- Enable irq before drm_dev_register.

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
hifive-unleashed-5.2
james qian wang (Arm Technology China) 2019-01-22 09:24:25 +00:00 committed by Liviu Dudau
parent 321e925c58
commit 0dac37bf1c
6 changed files with 346 additions and 2 deletions

View File

@ -9,6 +9,240 @@
#include "d71_dev.h"
#include "malidp_io.h"
static u64 get_lpu_event(struct d71_pipeline *d71_pipeline)
{
u32 __iomem *reg = d71_pipeline->lpu_addr;
u32 status, raw_status;
u64 evts = 0ULL;
raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
if (raw_status & LPU_IRQ_IBSY)
evts |= KOMEDA_EVENT_IBSY;
if (raw_status & LPU_IRQ_EOW)
evts |= KOMEDA_EVENT_EOW;
if (raw_status & (LPU_IRQ_ERR | LPU_IRQ_IBSY)) {
u32 restore = 0, tbu_status;
/* Check error of LPU status */
status = malidp_read32(reg, BLK_STATUS);
if (status & LPU_STATUS_AXIE) {
restore |= LPU_STATUS_AXIE;
evts |= KOMEDA_ERR_AXIE;
}
if (status & LPU_STATUS_ACE0) {
restore |= LPU_STATUS_ACE0;
evts |= KOMEDA_ERR_ACE0;
}
if (status & LPU_STATUS_ACE1) {
restore |= LPU_STATUS_ACE1;
evts |= KOMEDA_ERR_ACE1;
}
if (status & LPU_STATUS_ACE2) {
restore |= LPU_STATUS_ACE2;
evts |= KOMEDA_ERR_ACE2;
}
if (status & LPU_STATUS_ACE3) {
restore |= LPU_STATUS_ACE3;
evts |= KOMEDA_ERR_ACE3;
}
if (restore != 0)
malidp_write32_mask(reg, BLK_STATUS, restore, 0);
restore = 0;
/* Check errors of TBU status */
tbu_status = malidp_read32(reg, LPU_TBU_STATUS);
if (tbu_status & LPU_TBU_STATUS_TCF) {
restore |= LPU_TBU_STATUS_TCF;
evts |= KOMEDA_ERR_TCF;
}
if (tbu_status & LPU_TBU_STATUS_TTNG) {
restore |= LPU_TBU_STATUS_TTNG;
evts |= KOMEDA_ERR_TTNG;
}
if (tbu_status & LPU_TBU_STATUS_TITR) {
restore |= LPU_TBU_STATUS_TITR;
evts |= KOMEDA_ERR_TITR;
}
if (tbu_status & LPU_TBU_STATUS_TEMR) {
restore |= LPU_TBU_STATUS_TEMR;
evts |= KOMEDA_ERR_TEMR;
}
if (tbu_status & LPU_TBU_STATUS_TTF) {
restore |= LPU_TBU_STATUS_TTF;
evts |= KOMEDA_ERR_TTF;
}
if (restore != 0)
malidp_write32_mask(reg, LPU_TBU_STATUS, restore, 0);
}
malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
return evts;
}
static u64 get_cu_event(struct d71_pipeline *d71_pipeline)
{
u32 __iomem *reg = d71_pipeline->cu_addr;
u32 status, raw_status;
u64 evts = 0ULL;
raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
if (raw_status & CU_IRQ_OVR)
evts |= KOMEDA_EVENT_OVR;
if (raw_status & (CU_IRQ_ERR | CU_IRQ_OVR)) {
status = malidp_read32(reg, BLK_STATUS) & 0x7FFFFFFF;
if (status & CU_STATUS_CPE)
evts |= KOMEDA_ERR_CPE;
if (status & CU_STATUS_ZME)
evts |= KOMEDA_ERR_ZME;
if (status & CU_STATUS_CFGE)
evts |= KOMEDA_ERR_CFGE;
if (status)
malidp_write32_mask(reg, BLK_STATUS, status, 0);
}
malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
return evts;
}
static u64 get_dou_event(struct d71_pipeline *d71_pipeline)
{
u32 __iomem *reg = d71_pipeline->dou_addr;
u32 status, raw_status;
u64 evts = 0ULL;
raw_status = malidp_read32(reg, BLK_IRQ_RAW_STATUS);
if (raw_status & DOU_IRQ_PL0)
evts |= KOMEDA_EVENT_VSYNC;
if (raw_status & DOU_IRQ_UND)
evts |= KOMEDA_EVENT_URUN;
if (raw_status & (DOU_IRQ_ERR | DOU_IRQ_UND)) {
u32 restore = 0;
status = malidp_read32(reg, BLK_STATUS);
if (status & DOU_STATUS_DRIFTTO) {
restore |= DOU_STATUS_DRIFTTO;
evts |= KOMEDA_ERR_DRIFTTO;
}
if (status & DOU_STATUS_FRAMETO) {
restore |= DOU_STATUS_FRAMETO;
evts |= KOMEDA_ERR_FRAMETO;
}
if (status & DOU_STATUS_TETO) {
restore |= DOU_STATUS_TETO;
evts |= KOMEDA_ERR_TETO;
}
if (status & DOU_STATUS_CSCE) {
restore |= DOU_STATUS_CSCE;
evts |= KOMEDA_ERR_CSCE;
}
if (restore != 0)
malidp_write32_mask(reg, BLK_STATUS, restore, 0);
}
malidp_write32(reg, BLK_IRQ_CLEAR, raw_status);
return evts;
}
static u64 get_pipeline_event(struct d71_pipeline *d71_pipeline, u32 gcu_status)
{
u32 evts = 0ULL;
if (gcu_status & (GLB_IRQ_STATUS_LPU0 | GLB_IRQ_STATUS_LPU1))
evts |= get_lpu_event(d71_pipeline);
if (gcu_status & (GLB_IRQ_STATUS_CU0 | GLB_IRQ_STATUS_CU1))
evts |= get_cu_event(d71_pipeline);
if (gcu_status & (GLB_IRQ_STATUS_DOU0 | GLB_IRQ_STATUS_DOU1))
evts |= get_dou_event(d71_pipeline);
return evts;
}
static irqreturn_t
d71_irq_handler(struct komeda_dev *mdev, struct komeda_events *evts)
{
struct d71_dev *d71 = mdev->chip_data;
u32 status, gcu_status, raw_status;
gcu_status = malidp_read32(d71->gcu_addr, GLB_IRQ_STATUS);
if (gcu_status & GLB_IRQ_STATUS_GCU) {
raw_status = malidp_read32(d71->gcu_addr, BLK_IRQ_RAW_STATUS);
if (raw_status & GCU_IRQ_CVAL0)
evts->pipes[0] |= KOMEDA_EVENT_FLIP;
if (raw_status & GCU_IRQ_CVAL1)
evts->pipes[1] |= KOMEDA_EVENT_FLIP;
if (raw_status & GCU_IRQ_ERR) {
status = malidp_read32(d71->gcu_addr, BLK_STATUS);
if (status & GCU_STATUS_MERR) {
evts->global |= KOMEDA_ERR_MERR;
malidp_write32_mask(d71->gcu_addr, BLK_STATUS,
GCU_STATUS_MERR, 0);
}
}
malidp_write32(d71->gcu_addr, BLK_IRQ_CLEAR, raw_status);
}
if (gcu_status & GLB_IRQ_STATUS_PIPE0)
evts->pipes[0] |= get_pipeline_event(d71->pipes[0], gcu_status);
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;
}
#define ENABLED_GCU_IRQS (GCU_IRQ_CVAL0 | GCU_IRQ_CVAL1 | \
GCU_IRQ_MODE | GCU_IRQ_ERR)
#define ENABLED_LPU_IRQS (LPU_IRQ_IBSY | LPU_IRQ_ERR | LPU_IRQ_EOW)
#define ENABLED_CU_IRQS (CU_IRQ_OVR | CU_IRQ_ERR)
#define ENABLED_DOU_IRQS (DOU_IRQ_UND | DOU_IRQ_ERR)
static int d71_enable_irq(struct komeda_dev *mdev)
{
struct d71_dev *d71 = mdev->chip_data;
struct d71_pipeline *pipe;
u32 i;
malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK,
ENABLED_GCU_IRQS, ENABLED_GCU_IRQS);
for (i = 0; i < d71->num_pipelines; i++) {
pipe = d71->pipes[i];
malidp_write32_mask(pipe->cu_addr, BLK_IRQ_MASK,
ENABLED_CU_IRQS, ENABLED_CU_IRQS);
malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,
ENABLED_LPU_IRQS, ENABLED_LPU_IRQS);
malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,
ENABLED_DOU_IRQS, ENABLED_DOU_IRQS);
}
return 0;
}
static int d71_disable_irq(struct komeda_dev *mdev)
{
struct d71_dev *d71 = mdev->chip_data;
struct d71_pipeline *pipe;
u32 i;
malidp_write32_mask(d71->gcu_addr, BLK_IRQ_MASK, ENABLED_GCU_IRQS, 0);
for (i = 0; i < d71->num_pipelines; i++) {
pipe = d71->pipes[i];
malidp_write32_mask(pipe->cu_addr, BLK_IRQ_MASK,
ENABLED_CU_IRQS, 0);
malidp_write32_mask(pipe->lpu_addr, BLK_IRQ_MASK,
ENABLED_LPU_IRQS, 0);
malidp_write32_mask(pipe->dou_addr, BLK_IRQ_MASK,
ENABLED_DOU_IRQS, 0);
}
return 0;
}
static int d71_reset(struct d71_dev *d71)
{
u32 __iomem *gcu = d71->gcu_addr;
@ -222,6 +456,9 @@ static 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,
};
struct komeda_dev_funcs *

View File

@ -18,6 +18,24 @@
#include "komeda_dev.h"
#include "komeda_kms.h"
void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
struct komeda_events *evts)
{
struct drm_crtc *crtc = &kcrtc->base;
u32 events = evts->pipes[kcrtc->master->id];
if (events & KOMEDA_EVENT_VSYNC)
drm_crtc_handle_vblank(crtc);
/* will handle it together with the write back support */
if (events & KOMEDA_EVENT_EOW)
DRM_DEBUG("EOW.\n");
/* will handle it with crtc->flush */
if (events & KOMEDA_EVENT_FLIP)
DRM_DEBUG("FLIP Done.\n");
}
struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
};

View File

@ -53,6 +53,7 @@ static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
{
struct platform_device *pdev = to_platform_device(dev);
struct device_node *child, *np = dev->of_node;
struct clk *clk;
int ret;
@ -62,6 +63,11 @@ static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
return PTR_ERR(clk);
mdev->mclk = clk;
mdev->irq = platform_get_irq(pdev, 0);
if (mdev->irq < 0) {
DRM_ERROR("could not get IRQ number.\n");
return mdev->irq;
}
for_each_available_child_of_node(np, child) {
if (of_node_cmp(child->name, "pipeline") == 0) {

View File

@ -13,6 +13,33 @@
#include "malidp_product.h"
#include "komeda_format_caps.h"
#define KOMEDA_EVENT_VSYNC BIT_ULL(0)
#define KOMEDA_EVENT_FLIP BIT_ULL(1)
#define KOMEDA_EVENT_URUN BIT_ULL(2)
#define KOMEDA_EVENT_IBSY BIT_ULL(3)
#define KOMEDA_EVENT_OVR BIT_ULL(4)
#define KOMEDA_EVENT_EOW BIT_ULL(5)
#define KOMEDA_EVENT_MODE BIT_ULL(6)
#define KOMEDA_ERR_TETO BIT_ULL(14)
#define KOMEDA_ERR_TEMR BIT_ULL(15)
#define KOMEDA_ERR_TITR BIT_ULL(16)
#define KOMEDA_ERR_CPE BIT_ULL(17)
#define KOMEDA_ERR_CFGE BIT_ULL(18)
#define KOMEDA_ERR_AXIE BIT_ULL(19)
#define KOMEDA_ERR_ACE0 BIT_ULL(20)
#define KOMEDA_ERR_ACE1 BIT_ULL(21)
#define KOMEDA_ERR_ACE2 BIT_ULL(22)
#define KOMEDA_ERR_ACE3 BIT_ULL(23)
#define KOMEDA_ERR_DRIFTTO BIT_ULL(24)
#define KOMEDA_ERR_FRAMETO BIT_ULL(25)
#define KOMEDA_ERR_CSCE BIT_ULL(26)
#define KOMEDA_ERR_ZME BIT_ULL(27)
#define KOMEDA_ERR_MERR BIT_ULL(28)
#define KOMEDA_ERR_TCF BIT_ULL(29)
#define KOMEDA_ERR_TTNG BIT_ULL(30)
#define KOMEDA_ERR_TTF BIT_ULL(31)
/* malidp device id */
enum {
MALI_D71 = 0,
@ -39,6 +66,11 @@ struct komeda_product_data {
struct komeda_dev;
struct komeda_events {
u64 global;
u64 pipes[KOMEDA_MAX_PIPELINES];
};
/**
* struct komeda_dev_funcs
*
@ -60,6 +92,17 @@ struct komeda_dev_funcs {
int (*enum_resources)(struct komeda_dev *mdev);
/** @cleanup: call to chip to cleanup komeda_dev->chip data */
void (*cleanup)(struct komeda_dev *mdev);
/**
* @irq_handler:
*
* for CORE to get the HW event from the CHIP when interrupt happened.
*/
irqreturn_t (*irq_handler)(struct komeda_dev *mdev,
struct komeda_events *events);
/** @enable_irq: enable irq */
int (*enable_irq)(struct komeda_dev *mdev);
/** @disable_irq: disable irq */
int (*disable_irq)(struct komeda_dev *mdev);
};
/**
@ -81,6 +124,9 @@ struct komeda_dev {
/** @mck: HW main engine clk */
struct clk *mclk;
/** @irq: irq number */
int irq;
int n_pipelines;
struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];

View File

@ -13,6 +13,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_irq.h>
#include <drm/drm_vblank.h>
#include "komeda_dev.h"
@ -33,10 +34,31 @@ static int komeda_gem_cma_dumb_create(struct drm_file *file,
return drm_gem_cma_dumb_create_internal(file, dev, args);
}
static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
{
struct drm_device *drm = data;
struct komeda_dev *mdev = drm->dev_private;
struct komeda_kms_dev *kms = to_kdev(drm);
struct komeda_events evts;
irqreturn_t status;
u32 i;
/* Call into the CHIP to recognize events */
memset(&evts, 0, sizeof(evts));
status = mdev->funcs->irq_handler(mdev, &evts);
/* Notify the crtc to handle the events */
for (i = 0; i < kms->n_crtcs; i++)
komeda_crtc_handle_event(&kms->crtcs[i], &evts);
return status;
}
static struct drm_driver komeda_kms_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
DRIVER_PRIME,
DRIVER_PRIME | DRIVER_HAVE_IRQ,
.lastclose = drm_fb_helper_lastclose,
.irq_handler = komeda_kms_irq_handler,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = komeda_gem_cma_dumb_create,
@ -144,12 +166,22 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
drm_mode_config_reset(drm);
err = drm_dev_register(drm, 0);
err = drm_irq_install(drm, mdev->irq);
if (err)
goto cleanup_mode_config;
err = mdev->funcs->enable_irq(mdev);
if (err)
goto uninstall_irq;
err = drm_dev_register(drm, 0);
if (err)
goto uninstall_irq;
return kms;
uninstall_irq:
drm_irq_uninstall(drm);
cleanup_mode_config:
drm_mode_config_cleanup(drm);
free_kms:
@ -162,7 +194,9 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
struct drm_device *drm = &kms->base;
struct komeda_dev *mdev = drm->dev_private;
mdev->funcs->disable_irq(mdev);
drm_dev_unregister(drm);
drm_irq_uninstall(drm);
component_unbind_all(mdev->dev, drm);
komeda_kms_cleanup_private_objs(mdev);
drm_mode_config_cleanup(drm);

View File

@ -110,6 +110,9 @@ int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
struct komeda_dev *mdev);
void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
void komeda_crtc_handle_event(struct komeda_crtc *kcrtc,
struct komeda_events *evts);
struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
void komeda_kms_detach(struct komeda_kms_dev *kms);