On Thu, Jul 15, 2021 at 09:58:09AM +0800, lichenyang wrote: > Add LS7A DC vsync interrupt enable and close function, and > register irq_handler function interface. > Add vbrank event processing flow. > > V2: > - Remove the useless flags parameter. Do this in a separate patch. It is an unrelated cleanup. > - Added error handling in the loongson_drm_load function. > > Signed-off-by: lichenyang <lichenyang@xxxxxxxxxxx> > --- > drivers/gpu/drm/loongson/Makefile | 3 +- > drivers/gpu/drm/loongson/loongson_crtc.c | 43 +++++++++- > drivers/gpu/drm/loongson/loongson_drv.c | 22 +++-- > drivers/gpu/drm/loongson/loongson_drv.h | 17 +++- > drivers/gpu/drm/loongson/loongson_irq.c | 105 +++++++++++++++++++++++ > 5 files changed, 179 insertions(+), 11 deletions(-) > create mode 100644 drivers/gpu/drm/loongson/loongson_irq.c > > diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile > index 773b806e99a2..cc50b65c7e03 100644 > --- a/drivers/gpu/drm/loongson/Makefile > +++ b/drivers/gpu/drm/loongson/Makefile > @@ -11,5 +11,6 @@ loongson-y := loongson_drv.o \ > loongson_device.o \ > loongson_connector.o \ > loongson_encoder.o \ > - loongson_i2c.o > + loongson_i2c.o \ > + loongson_irq.o > obj-$(CONFIG_DRM_LOONGSON) += loongson.o > diff --git a/drivers/gpu/drm/loongson/loongson_crtc.c b/drivers/gpu/drm/loongson/loongson_crtc.c > index 4cb65fa08778..4c62d5b2bd56 100644 > --- a/drivers/gpu/drm/loongson/loongson_crtc.c > +++ b/drivers/gpu/drm/loongson/loongson_crtc.c > @@ -154,19 +154,25 @@ static void loongson_crtc_mode_set_nofb(struct drm_crtc *crtc) > } > > static void loongson_crtc_atomic_enable(struct drm_crtc *crtc, > - struct drm_atomic_state *old_state) > + struct drm_atomic_state *old_crtc_state) > { > struct drm_device *dev = crtc->dev; > struct loongson_device *ldev = dev->dev_private; > struct loongson_crtc *lcrtc = to_loongson_crtc(crtc); > u32 reg_offset = lcrtc->reg_offset; > > + if (lcrtc->cfg_reg & CFG_ENABLE) > + goto vblank_on; > + > lcrtc->cfg_reg |= CFG_ENABLE; > ls7a_mm_wreg(ldev, FB_CFG_REG + reg_offset, lcrtc->cfg_reg); > + > +vblank_on: > + drm_crtc_vblank_on(crtc); > } > > static void loongson_crtc_atomic_disable(struct drm_crtc *crtc, > - struct drm_atomic_state *old_state) > + struct drm_atomic_state *old_crtc_state) > { > struct drm_device *dev = crtc->dev; > struct loongson_device *ldev = dev->dev_private; > @@ -175,10 +181,36 @@ static void loongson_crtc_atomic_disable(struct drm_crtc *crtc, > > lcrtc->cfg_reg &= ~CFG_ENABLE; > ls7a_mm_wreg(ldev, FB_CFG_REG + reg_offset, lcrtc->cfg_reg); > + > + spin_lock_irq(&crtc->dev->event_lock); > + if (crtc->state->event) { > + drm_crtc_send_vblank_event(crtc, crtc->state->event); > + crtc->state->event = NULL; > + } > + spin_unlock_irq(&crtc->dev->event_lock); > + > + drm_crtc_vblank_off(crtc); > +} > + > +static void loongson_crtc_atomic_flush(struct drm_crtc *crtc, > + struct drm_crtc_state *old_crtc_state) > +{ > + struct drm_pending_vblank_event *event = crtc->state->event; > + > + if (event) { Flip this around: if (!event) return; > + crtc->state->event = NULL; > + > + spin_lock_irq(&crtc->dev->event_lock); > + if (drm_crtc_vblank_get(crtc) == 0) > + drm_crtc_arm_vblank_event(crtc, event); > + else > + drm_crtc_send_vblank_event(crtc, event); > + spin_unlock_irq(&crtc->dev->event_lock); > + } > } > > static enum drm_mode_status loongson_mode_valid(struct drm_crtc *crtc, > - const struct drm_display_mode *mode) > + const struct drm_display_mode *mode) > { > if (mode->hdisplay > 1920) > return MODE_BAD; > @@ -194,9 +226,10 @@ static enum drm_mode_status loongson_mode_valid(struct drm_crtc *crtc, > > static const struct drm_crtc_helper_funcs loongson_crtc_helper_funcs = { > .mode_valid = loongson_mode_valid, > + .mode_set_nofb = loongson_crtc_mode_set_nofb, > + .atomic_flush = loongson_crtc_atomic_flush, > .atomic_enable = loongson_crtc_atomic_enable, > .atomic_disable = loongson_crtc_atomic_disable, > - .mode_set_nofb = loongson_crtc_mode_set_nofb, > }; > > static const struct drm_crtc_funcs loongson_crtc_funcs = { > @@ -206,6 +239,8 @@ static const struct drm_crtc_funcs loongson_crtc_funcs = { > .destroy = drm_crtc_cleanup, > .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, > .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, > + .enable_vblank = loongson_crtc_enable_vblank, > + .disable_vblank = loongson_crtc_disable_vblank, > }; > > int loongson_crtc_init(struct loongson_device *ldev, int index) > diff --git a/drivers/gpu/drm/loongson/loongson_drv.c b/drivers/gpu/drm/loongson/loongson_drv.c > index 252be9e25aff..13003f6ae062 100644 > --- a/drivers/gpu/drm/loongson/loongson_drv.c > +++ b/drivers/gpu/drm/loongson/loongson_drv.c > @@ -24,7 +24,7 @@ static const struct drm_mode_config_funcs loongson_mode_funcs = { > .mode_valid = drm_vram_helper_mode_valid > }; > > -static int loongson_device_init(struct drm_device *dev, uint32_t flags) > +static int loongson_device_init(struct drm_device *dev) > { > struct loongson_device *ldev = dev->dev_private; > struct pci_dev *gpu_pdev; > @@ -131,7 +131,7 @@ int loongson_modeset_init(struct loongson_device *ldev) > return 0; > } > > -static int loongson_drm_load(struct drm_device *dev, unsigned long flags) > +static int loongson_drm_load(struct drm_device *dev) > { > struct loongson_device *ldev; > int ret; > @@ -143,7 +143,7 @@ static int loongson_drm_load(struct drm_device *dev, unsigned long flags) > dev->dev_private = ldev; > ldev->dev = dev; > > - ret = loongson_device_init(dev, flags); > + ret = loongson_device_init(dev); > if (ret) > goto err; > > @@ -164,8 +164,16 @@ static int loongson_drm_load(struct drm_device *dev, unsigned long flags) > pci_set_drvdata(dev->pdev, dev); > > ret = loongson_modeset_init(ldev); > - if (ret) > + if (ret) { > dev_err(dev->dev, "Fatal error during modeset init: %d\n", ret); > + goto err; > + } > + > + ret = loongson_irq_init(ldev); > + if (ret) { > + dev_err(dev->dev, "Fatal error during irq init: %d\n", ret); > + goto err; > + } > > drm_kms_helper_poll_init(dev); > drm_mode_config_reset(dev); > @@ -192,6 +200,10 @@ static struct drm_driver loongson_drm_driver = { > .fops = &fops, > DRM_GEM_VRAM_DRIVER, > > + .irq_handler = loongson_irq_handler, > + .irq_preinstall = loongson_irq_preinstall, > + .irq_uninstall = loongson_irq_uninstall, > + > .name = DRIVER_NAME, > .desc = DRIVER_DESC, > .date = DRIVER_DATE, > @@ -221,7 +233,7 @@ static int loongson_pci_probe(struct pci_dev *pdev, > goto err_free; > } > > - ret = loongson_drm_load(dev, 0x0); > + ret = loongson_drm_load(dev); > if (ret) { > drm_err(dev, "failed to load loongson: %d\n", ret); > goto err_pdev; > diff --git a/drivers/gpu/drm/loongson/loongson_drv.h b/drivers/gpu/drm/loongson/loongson_drv.h > index 24a534c3c79c..60f5bd48f7f2 100644 > --- a/drivers/gpu/drm/loongson/loongson_drv.h > +++ b/drivers/gpu/drm/loongson/loongson_drv.h > @@ -4,9 +4,11 @@ > #define __LOONGSON_DRV_H__ > > #include <drm/drm_drv.h> > +#include <drm/drm_fourcc.h> > +#include <drm/drm_vblank.h> > #include <drm/drm_gem.h> > +#include <drm/drm_irq.h> > #include <drm/drm_fb_helper.h> > -#include <drm/drm_fourcc.h> > #include <drm/drm_probe_helper.h> > #include <drm/drm_atomic.h> > #include <drm/drm_atomic_helper.h> > @@ -49,6 +51,7 @@ > #define FB_HSYNC_REG (0x1420) > #define FB_VDISPLAY_REG (0x1480) > #define FB_VSYNC_REG (0x14a0) > +#define FB_INT_REG (0x1570) > > #define CFG_FMT GENMASK(2, 0) > #define CFG_FBSWITCH BIT(7) > @@ -60,6 +63,10 @@ > #define FB_PANCFG_DEF 0x80001311 > #define FB_HSYNC_PULSE (1 << 30) > #define FB_VSYNC_PULSE (1 << 30) > +#define FB_VSYNC1_ENABLE (1 << 16) > +#define FB_VSYNC0_ENABLE (1 << 18) > +#define FB_VSYNC1_INT (1 << 0) > +#define FB_VSYNC0_INT (1 << 2) > > /* PIX PLL */ > #define LOOPC_MIN 24 > @@ -136,6 +143,14 @@ int loongson_encoder_init(struct loongson_device *ldev, int index); > /* plane */ > int loongson_plane_init(struct loongson_crtc *lcrtc); > > +/* irq */ > +int loongson_irq_init(struct loongson_device *ldev); > +int loongson_crtc_enable_vblank(struct drm_crtc *crtc); > +void loongson_crtc_disable_vblank(struct drm_crtc *crtc); > +irqreturn_t loongson_irq_handler(int irq, void *arg); > +void loongson_irq_preinstall(struct drm_device *dev); > +void loongson_irq_uninstall(struct drm_device *dev); > + > /* i2c */ > int loongson_dc_gpio_init(struct loongson_device *ldev); > > diff --git a/drivers/gpu/drm/loongson/loongson_irq.c b/drivers/gpu/drm/loongson/loongson_irq.c > new file mode 100644 > index 000000000000..d212e16f3c00 > --- /dev/null > +++ b/drivers/gpu/drm/loongson/loongson_irq.c > @@ -0,0 +1,105 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +#include "loongson_drv.h" > +#include <linux/pci.h> > + > +int loongson_irq_init(struct loongson_device *ldev) > +{ > + struct drm_device *dev; > + int ret, irq; > + > + dev = ldev->dev; > + irq = dev->pdev->irq; > + > + ret = drm_vblank_init(dev, ldev->num_crtc); > + if (ret) { > + dev_err(dev->dev, "Fatal error during vblank init: %d\n", ret); > + return ret; > + } > + DRM_INFO("drm vblank init finished\n"); > + > + ret = drm_irq_install(dev, irq); > + if (ret) { > + dev_err(dev->dev, "Fatal error during irq install: %d\n", ret); > + return ret; > + } > + DRM_INFO("loongson irq initialized\n"); > + > + return 0; > +} > + > +int loongson_crtc_enable_vblank(struct drm_crtc *crtc) > +{ > + struct loongson_crtc *lcrtc = to_loongson_crtc(crtc); > + struct loongson_device *ldev = lcrtc->ldev; > + u32 reg_val; > + > + if (lcrtc->crtc_id) { > + reg_val = ls7a_mm_rreg(ldev, FB_INT_REG); > + reg_val |= FB_VSYNC1_ENABLE; > + ls7a_mm_wreg(ldev, FB_INT_REG, reg_val); > + } else { > + reg_val = ls7a_mm_rreg(ldev, FB_INT_REG); > + reg_val |= FB_VSYNC0_ENABLE; > + ls7a_mm_wreg(ldev, FB_INT_REG, reg_val); > + } > + > + return 0; > +} > + > +void loongson_crtc_disable_vblank(struct drm_crtc *crtc) > +{ > + struct loongson_crtc *lcrtc = to_loongson_crtc(crtc); > + struct loongson_device *ldev = lcrtc->ldev; > + u32 reg_val; > + > + if (lcrtc->crtc_id) { > + reg_val = ls7a_mm_rreg(ldev, FB_INT_REG); > + reg_val &= ~FB_VSYNC1_ENABLE; > + ls7a_mm_wreg(ldev, FB_INT_REG, reg_val); > + } else { > + reg_val = ls7a_mm_rreg(ldev, FB_INT_REG); > + reg_val &= ~FB_VSYNC0_ENABLE; > + ls7a_mm_wreg(ldev, FB_INT_REG, reg_val); > + } More readable to pull the common code in one place: reg_val = ls7a_mm_rreg(ldev, FB_INT_REG); if (lcrtc->crtc_id) reg_val &= ~FB_VSYNC1_ENABLE; else reg_val &= ~FB_VSYNC0_ENABLE; ls7a_mm_wreg(ldev, FB_INT_REG, reg_val); > +} > + regards, dan carpenter