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>
This commit is contained in:
parent
321e925c58
commit
0dac37bf1c
@ -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 *
|
||||
|
@ -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 = {
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user