From 07b9d70b285cb890f2be68f35409a5666614f1e0 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng <15330273260@189.cn> Date: Sat, 18 Mar 2023 20:17:54 +0800 Subject: [PATCH] drm/loongson: using hdmi hot plug status register LoongArch inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6ONR1 -------------------------------- remove ugly workaround, don't create platform device anymore Signed-off-by: Sui Jingfeng <15330273260@189.cn> Change-Id: I7934f66c8993b4d9d77a9fe04438849e1f6191ac --- drivers/gpu/drm/loongson/Makefile | 1 - drivers/gpu/drm/loongson/lsdc_crtc.c | 4 +- drivers/gpu/drm/loongson/lsdc_debugfs.c | 14 +- drivers/gpu/drm/loongson/lsdc_drv.c | 290 +++++++++++++++----- drivers/gpu/drm/loongson/lsdc_drv.h | 127 +++++++-- drivers/gpu/drm/loongson/lsdc_i2c.c | 16 +- drivers/gpu/drm/loongson/lsdc_i2c.h | 5 +- drivers/gpu/drm/loongson/lsdc_output.c | 148 ++++++----- drivers/gpu/drm/loongson/lsdc_pci_drv.c | 336 ------------------------ drivers/gpu/drm/loongson/lsdc_plane.c | 74 ++---- drivers/gpu/drm/loongson/lsdc_regs.h | 30 ++- 11 files changed, 485 insertions(+), 560 deletions(-) diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile index cf6391b8eb17..73c45144c0c7 100644 --- a/drivers/gpu/drm/loongson/Makefile +++ b/drivers/gpu/drm/loongson/Makefile @@ -8,7 +8,6 @@ loongson-y := \ lsdc_pll.o \ lsdc_i2c.o \ lsdc_output.o \ - lsdc_pci_drv.o \ lsdc_debugfs.o \ lsdc-$(CONFIG_DEBUG_FS) += lsdc_debugfs.o diff --git a/drivers/gpu/drm/loongson/lsdc_crtc.c b/drivers/gpu/drm/loongson/lsdc_crtc.c index e59b75d79098..a18dc0081592 100644 --- a/drivers/gpu/drm/loongson/lsdc_crtc.c +++ b/drivers/gpu/drm/loongson/lsdc_crtc.c @@ -168,7 +168,7 @@ lsdc_crtc_helper_mode_valid(struct drm_crtc *crtc, static int lsdc_pixpll_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { - struct lsdc_display_pipe * const dispipe = drm_crtc_to_dispipe(crtc); + struct lsdc_display_pipe * const dispipe = crtc_to_display_pipe(crtc); struct lsdc_pll * const pixpll = &dispipe->pixpll; const struct lsdc_pixpll_funcs * const pfuncs = pixpll->funcs; struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state); @@ -197,7 +197,7 @@ static int lsdc_crtc_helper_atomic_check(struct drm_crtc *crtc, static void lsdc_update_pixclk(struct drm_crtc *crtc) { - struct lsdc_display_pipe * const dispipe = drm_crtc_to_dispipe(crtc); + struct lsdc_display_pipe * const dispipe = crtc_to_display_pipe(crtc); struct lsdc_pll * const pixpll = &dispipe->pixpll; const struct lsdc_pixpll_funcs * const clkfun = pixpll->funcs; struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(crtc->state); diff --git a/drivers/gpu/drm/loongson/lsdc_debugfs.c b/drivers/gpu/drm/loongson/lsdc_debugfs.c index 1aad413ee97c..8ffb181cb048 100644 --- a/drivers/gpu/drm/loongson/lsdc_debugfs.c +++ b/drivers/gpu/drm/loongson/lsdc_debugfs.c @@ -82,9 +82,10 @@ static const struct { } lsdc_regs_array[] = { REGDEF(INT), REGDEF(CRTC0_CFG), - REGDEF(CRTC0_FB_ADDR0), - REGDEF(CRTC0_FB_ADDR1), - REGDEF(CRTC0_FB_HI_ADDR), + REGDEF(CRTC0_FB0_LO_ADDR), + REGDEF(CRTC0_FB0_HI_ADDR), + REGDEF(CRTC0_FB1_LO_ADDR), + REGDEF(CRTC0_FB1_HI_ADDR), REGDEF(CRTC0_STRIDE), REGDEF(CRTC0_FB_ORIGIN), REGDEF(CRTC0_HDISPLAY), @@ -94,9 +95,10 @@ static const struct { REGDEF(CRTC0_GAMMA_INDEX), REGDEF(CRTC0_GAMMA_DATA), REGDEF(CRTC1_CFG), - REGDEF(CRTC1_FB_ADDR0), - REGDEF(CRTC1_FB_ADDR1), - REGDEF(CRTC1_FB_HI_ADDR), + REGDEF(CRTC1_FB0_LO_ADDR), + REGDEF(CRTC1_FB0_HI_ADDR), + REGDEF(CRTC1_FB1_LO_ADDR), + REGDEF(CRTC1_FB1_HI_ADDR), REGDEF(CRTC1_STRIDE), REGDEF(CRTC1_FB_ORIGIN), REGDEF(CRTC1_HDISPLAY), diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c index 306b0de0d2e8..4fa1d4c3b9f0 100644 --- a/drivers/gpu/drm/loongson/lsdc_drv.c +++ b/drivers/gpu/drm/loongson/lsdc_drv.c @@ -11,6 +11,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -20,11 +24,26 @@ #include #include #include +#include #include "lsdc_drv.h" #include "lsdc_irq.h" #include "lsdc_output.h" #include "lsdc_debugfs.h" +#include "lsdc_i2c.h" + +static int lsdc_use_vram_helper = -1; +MODULE_PARM_DESC(use_vram_helper, "Using vram helper based driver(0 = disabled)"); +module_param_named(use_vram_helper, lsdc_use_vram_helper, int, 0644); + +static int lsdc_gamma = -1; +MODULE_PARM_DESC(gamma, "enable gamma (-1 = disabled (default), >0 = enabled)"); +module_param_named(gamma, lsdc_gamma, int, 0644); + +static int lsdc_relax_alignment = -1; +MODULE_PARM_DESC(relax_alignment, + "relax crtc stride alignment (-1 = disabled (default), >0 = enabled)"); +module_param_named(relax_alignment, lsdc_relax_alignment, int, 0644); static const struct lsdc_chip_desc dc_in_ls2k1000 = { .chip = LSDC_CHIP_2K1000, @@ -125,30 +144,9 @@ static int lsdc_gem_cma_dumb_create(struct drm_file *file, return drm_gem_cma_dumb_create_internal(file, ddev, args); } -DEFINE_DRM_GEM_CMA_FOPS(lsdc_drv_fops); - -static struct drm_driver lsdc_drm_driver_cma_stub = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - .lastclose = drm_fb_helper_lastclose, - .fops = &lsdc_drv_fops, - - .name = "lsdc", - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, - - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(lsdc_gem_cma_dumb_create), - -#ifdef CONFIG_DEBUG_FS - .debugfs_init = lsdc_debugfs_init, -#endif -}; - DEFINE_DRM_GEM_FOPS(lsdc_gem_fops); -static struct drm_driver lsdc_vram_driver_stub = { +static struct drm_driver lsdc_vram_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, .fops = &lsdc_gem_fops, @@ -168,7 +166,7 @@ static struct drm_driver lsdc_vram_driver_stub = { static int lsdc_modeset_init(struct lsdc_device *ldev, uint32_t num_crtc) { - struct drm_device *ddev = ldev->ddev; + struct drm_device *ddev = &ldev->ddev; unsigned int i; int ret; @@ -226,7 +224,7 @@ static int lsdc_modeset_init(struct lsdc_device *ldev, uint32_t num_crtc) static int lsdc_mode_config_init(struct lsdc_device *ldev) { const struct lsdc_chip_desc * const descp = ldev->desc; - struct drm_device *ddev = ldev->ddev; + struct drm_device *ddev = &ldev->ddev; int ret; ret = drmm_mode_config_init(ddev); @@ -250,13 +248,6 @@ static int lsdc_mode_config_init(struct lsdc_device *ldev) return lsdc_modeset_init(ldev, descp->num_of_crtc); } -static void lsdc_mode_config_fini(struct drm_device *ddev) -{ - drm_atomic_helper_shutdown(ddev); - - drm_mode_config_cleanup(ddev); -} - /* * lsdc_detect_chip - a function to tell different chips apart. */ @@ -308,7 +299,7 @@ lsdc_detect_chip(struct pci_dev *pdev, const struct pci_device_id * const ent) return NULL; } -static int lsdc_remove_conflicting_framebuffers(const struct drm_driver *drv) +static int lsdc_remove_conflicting_framebuffers(void) { struct apertures_struct *ap; @@ -316,39 +307,99 @@ static int lsdc_remove_conflicting_framebuffers(const struct drm_driver *drv) if (!ap) return -ENOMEM; - /* lsdc is a pci device, but it don't have a dedicate vram bar because - * of historic reason. The display controller is ported from Loongson - * 2H series SoC which date back to 2012. - * And simplefb node may have been located anywhere in memory. - */ - ap->ranges[0].base = 0; ap->ranges[0].size = ~0; return drm_fb_helper_remove_conflicting_framebuffers(ap, "loongsondrmfb", false); } -static int lsdc_platform_probe(struct platform_device *pdev) +static int lsdc_vram_init(struct lsdc_device *ldev) +{ + const struct lsdc_chip_desc * const descp = ldev->desc; + struct pci_dev *gpu; + resource_size_t base, size; + + if (descp->chip == LSDC_CHIP_7A2000) { + /* BAR 2 of LS7A2000's GPU contain VRAM */ + gpu = pci_get_device(PCI_VENDOR_ID_LOONGSON, 0x7A25, NULL); + } else if (descp->chip == LSDC_CHIP_7A1000) { + /* BAR 2 of LS7A1000's GPU(GC1000) contain VRAM */ + gpu = pci_get_device(PCI_VENDOR_ID_LOONGSON, 0x7A15, NULL); + } else { + drm_err(&ldev->ddev, "Unknown chip, the driver need update\n"); + return -ENOENT; + } + + base = pci_resource_start(gpu, 2); + size = pci_resource_len(gpu, 2); + + ldev->vram_base = base; + ldev->vram_size = size; + + drm_info(&ldev->ddev, "vram start: 0x%llx, size: %uMB\n", + (u64)base, (u32)(size >> 20)); + + return 0; +} + +static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct lsdc_device *ldev = dev_get_drvdata(pdev->dev.parent); - struct drm_driver *driver; + struct lsdc_device *ldev; struct drm_device *ddev; + const struct lsdc_chip_desc *descp; int ret; - if (ldev->use_vram_helper) - driver = &lsdc_vram_driver_stub; + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); + if (ret) + return ret; + + descp = lsdc_detect_chip(pdev, ent); + if (!descp) { + pr_info("unknown dc ip core, abort\n"); + return -ENOENT; + } + + lsdc_remove_conflicting_framebuffers(); + + ldev = devm_drm_dev_alloc(&pdev->dev, &lsdc_vram_driver, struct lsdc_device, ddev); + if (IS_ERR(ldev)) + return PTR_ERR(ldev); + + ldev->desc = descp; + ldev->use_vram_helper = lsdc_use_vram_helper && descp->has_vram; + + ddev = &ldev->ddev; + ddev->pdev = pdev; + + pci_set_drvdata(pdev, ddev); + + if (!descp->broken_gamma) + ldev->enable_gamma = true; else - driver = &lsdc_drm_driver_cma_stub; + ldev->enable_gamma = lsdc_gamma > 0 ? true : false; + + ldev->relax_alignment = lsdc_relax_alignment > 0 ? true : false; - lsdc_remove_conflicting_framebuffers(driver); + /* BAR 0 of the DC device contain registers base address */ + ldev->reg_base = pcim_iomap(pdev, 0, 0); + if (!ldev->reg_base) + return -ENODEV; - ddev = drm_dev_alloc(driver, &pdev->dev); - if (IS_ERR(ddev)) - return PTR_ERR(ddev); + if (ldev->use_vram_helper) { + ret = lsdc_vram_init(ldev); + if (ret) { + drm_err(ddev, "VRAM is unavailable\n"); + ldev->use_vram_helper = false; + } + } - platform_set_drvdata(pdev, ddev); - ldev->ddev = ddev; - ddev->dev_private = ldev; + ldev->irq = pdev->irq; if (ldev->use_vram_helper) { ret = drmm_vram_helper_init(ddev, ldev->vram_base, ldev->vram_size); @@ -358,13 +409,18 @@ static int lsdc_platform_probe(struct platform_device *pdev) } }; + spin_lock_init(&ldev->reglock); + ret = lsdc_mode_config_init(ldev); if (ret) { drm_dbg(ddev, "%s: %d\n", __func__, ret); goto err_kms; } - ret = devm_request_threaded_irq(&pdev->dev, ldev->irq, + drm_mode_config_reset(ddev); + + ret = devm_request_threaded_irq(&pdev->dev, + ldev->irq, lsdc_irq_handler_cb, lsdc_irq_thread_cb, IRQF_ONESHOT, NULL, @@ -378,8 +434,6 @@ static int lsdc_platform_probe(struct platform_device *pdev) if (ret) goto err_kms; - drm_mode_config_reset(ddev); - drm_kms_helper_poll_init(ddev); ret = drm_dev_register(ddev, 0); @@ -396,32 +450,134 @@ static int lsdc_platform_probe(struct platform_device *pdev) drm_dev_put(ddev); return ret; + } -static int lsdc_platform_remove(struct platform_device *pdev) +static void lsdc_pci_remove(struct pci_dev *pdev) { - struct drm_device *ddev = platform_get_drvdata(pdev); + struct drm_device *ddev = pci_get_drvdata(pdev); struct lsdc_device *ldev = to_lsdc(ddev); drm_dev_unregister(ddev); + drm_atomic_helper_shutdown(ddev); +} - drm_kms_helper_poll_fini(ddev); +static int lsdc_drm_freeze(struct drm_device *ddev) +{ + int error; - devm_free_irq(ddev->dev, ldev->irq, ddev); + error = drm_mode_config_helper_suspend(ddev); + if (error) + return error; - lsdc_mode_config_fini(ddev); + pci_save_state(to_pci_dev(ddev->dev)); - platform_set_drvdata(pdev, NULL); + return 0; +} - drm_dev_put(ddev); +static int lsdc_drm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + + return drm_mode_config_helper_resume(ddev); +} + +static int lsdc_pm_freeze(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *ddev = pci_get_drvdata(pdev); + + return lsdc_drm_freeze(ddev); +} + +static int lsdc_pm_thaw(struct device *dev) +{ + return lsdc_drm_resume(dev); +} + +static int lsdc_pm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int error; + + error = lsdc_pm_freeze(dev); + if (error) + return error; + + pci_save_state(pdev); + /* Shut down the device */ + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); return 0; } -struct platform_driver lsdc_platform_driver = { - .probe = lsdc_platform_probe, - .remove = lsdc_platform_remove, - .driver = { - .name = "lsdc", - }, +static int lsdc_pm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + if (pcim_enable_device(pdev)) + return -EIO; + + pci_set_power_state(pdev, PCI_D0); + + pci_restore_state(pdev); + + return lsdc_pm_thaw(dev); +} + +static const struct dev_pm_ops lsdc_pm_ops = { + .suspend = lsdc_pm_suspend, + .resume = lsdc_pm_resume, + .freeze = lsdc_pm_freeze, + .thaw = lsdc_pm_thaw, + .poweroff = lsdc_pm_freeze, + .restore = lsdc_pm_resume, +}; + +static const struct pci_device_id lsdc_pciid_list[] = { + {PCI_VENDOR_ID_LOONGSON, 0x7a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)LSDC_CHIP_7A1000}, + {PCI_VENDOR_ID_LOONGSON, 0x7a36, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)LSDC_CHIP_7A2000}, + {0, 0, 0, 0, 0, 0, 0} +}; + +static struct pci_driver lsdc_pci_driver = { + .name = DRIVER_NAME, + .id_table = lsdc_pciid_list, + .probe = lsdc_pci_probe, + .remove = lsdc_pci_remove, + .driver.pm = &lsdc_pm_ops, }; + +static int __init lsdc_drm_init(void) +{ + struct pci_dev *pdev = NULL; + + while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { + /* + * Multiple video card workaround + * + * This integrated video card will always be selected as + * default boot device by vgaarb subsystem. + */ + if (pdev->vendor != PCI_VENDOR_ID_LOONGSON) { + pr_info("Discrete graphic card detected, abort\n"); + return 0; + } + } + + return pci_register_driver(&lsdc_pci_driver); +} +module_init(lsdc_drm_init); + +static void __exit lsdc_drm_exit(void) +{ + pci_unregister_driver(&lsdc_pci_driver); +} +module_exit(lsdc_drm_exit); + +MODULE_DEVICE_TABLE(pci, lsdc_pciid_list); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h index e07b049dcd21..f10508173ea0 100644 --- a/drivers/gpu/drm/loongson/lsdc_drv.h +++ b/drivers/gpu/drm/loongson/lsdc_drv.h @@ -21,6 +21,7 @@ #include #include "lsdc_pll.h" +#include "lsdc_regs.h" #define DRIVER_AUTHOR "Sui Jingfeng " #define DRIVER_NAME "lsdc" @@ -57,19 +58,6 @@ struct lsdc_chip_desc { bool broken_gamma; }; -/* There is only a 1:1 mapping of encoders and connectors for lsdc */ -struct lsdc_output { - struct drm_encoder encoder; - struct drm_connector connector; - struct lsdc_i2c *li2c; -}; - -static inline struct lsdc_output * -drm_connector_to_lsdc_output(struct drm_connector *connp) -{ - return container_of(connp, struct lsdc_output, connector); -} - /* * struct lsdc_display_pipe - Abstraction of hardware display pipeline. * @crtc: CRTC control structure @@ -89,33 +77,50 @@ struct lsdc_display_pipe { struct drm_plane primary; struct drm_plane cursor; struct lsdc_pll pixpll; - struct lsdc_output *output; + struct drm_encoder encoder; + struct drm_connector connector; + struct lsdc_i2c *li2c; int index; bool available; }; static inline struct lsdc_display_pipe * -drm_crtc_to_dispipe(struct drm_crtc *crtc) +crtc_to_display_pipe(struct drm_crtc *crtc) { return container_of(crtc, struct lsdc_display_pipe, crtc); } static inline struct lsdc_display_pipe * -lsdc_cursor_to_dispipe(struct drm_plane *plane) +primary_to_display_pipe(struct drm_plane *plane) +{ + return container_of(plane, struct lsdc_display_pipe, primary); +} + +static inline struct lsdc_display_pipe * +cursor_to_display_pipe(struct drm_plane *plane) { return container_of(plane, struct lsdc_display_pipe, cursor); } +static inline struct lsdc_display_pipe * +connector_to_display_pipe(struct drm_connector *connector) +{ + return container_of(connector, struct lsdc_display_pipe, connector); +} + +static inline struct lsdc_display_pipe * +encoder_to_display_pipe(struct drm_encoder *encoder) +{ + return container_of(encoder, struct lsdc_display_pipe, encoder); +} + struct lsdc_crtc_state { struct drm_crtc_state base; struct lsdc_pll_core_values pparams; }; struct lsdc_device { - struct device *dev; - struct drm_device *ddev; - /* @dc: pointer to the platform device created at runtime */ - struct platform_device *dc; + struct drm_device ddev; /* @desc: device dependent data and feature descriptions */ const struct lsdc_chip_desc *desc; @@ -127,6 +132,9 @@ struct lsdc_device { struct lsdc_display_pipe dispipe[LSDC_NUM_CRTC]; + /* @reglock: protects concurrent register access */ + spinlock_t reglock; + /* * @num_output: count the number of active display pipe. */ @@ -158,7 +166,7 @@ struct lsdc_device { static inline struct lsdc_device *to_lsdc(struct drm_device *ddev) { - return ddev->dev_private; + return container_of(ddev, struct lsdc_device, ddev); } static inline struct lsdc_crtc_state * @@ -181,4 +189,81 @@ lsdc_detect_chip(struct pci_dev *pdev, const struct pci_device_id * const ent); extern struct platform_driver lsdc_platform_driver; +static inline u32 lsdc_rreg32(struct lsdc_device *ldev, u32 offset) +{ + return readl(ldev->reg_base + offset); +} + +static inline void lsdc_wreg32(struct lsdc_device *ldev, u32 offset, u32 val) +{ + writel(val, ldev->reg_base + offset); +} + +static inline void lsdc_ureg32_set(struct lsdc_device *ldev, + u32 offset, + u32 bit) +{ + void __iomem *addr = ldev->reg_base + offset; + u32 val = readl(addr); + + writel(val | bit, addr); +} + +static inline void lsdc_ureg32_clr(struct lsdc_device *ldev, + u32 offset, + u32 bit) +{ + void __iomem *addr = ldev->reg_base + offset; + u32 val = readl(addr); + + writel(val & ~bit, addr); +} + +static inline u32 lsdc_pipe_rreg32(struct lsdc_device *ldev, + u32 offset, + u32 pipe) +{ + return readl(ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET); +} + +#define lsdc_hdmi_rreg32 lsdc_pipe_rreg32 +#define lsdc_crtc_rreg32 lsdc_pipe_rreg32 + +static inline void lsdc_pipe_wreg32(struct lsdc_device *ldev, + u32 offset, + u32 pipe, + u32 val) +{ + writel(val, ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET); +} + +#define lsdc_hdmi_wreg32 lsdc_pipe_wreg32 +#define lsdc_crtc_wreg32 lsdc_pipe_wreg32 + +static inline void lsdc_crtc_ureg32_set(struct lsdc_device *ldev, + u32 offset, + u32 pipe, + u32 bit) +{ + void __iomem *addr; + u32 val; + + addr = ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET; + val = readl(addr); + writel(val | bit, addr); +} + +static inline void lsdc_crtc_ureg32_clr(struct lsdc_device *ldev, + u32 offset, + u32 pipe, + u32 bit) +{ + void __iomem *addr; + u32 val; + + addr = ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET; + val = readl(addr); + writel(val & ~bit, addr); +} + #endif diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.c b/drivers/gpu/drm/loongson/lsdc_i2c.c index ea64bd097a59..a6704054ce62 100644 --- a/drivers/gpu/drm/loongson/lsdc_i2c.c +++ b/drivers/gpu/drm/loongson/lsdc_i2c.c @@ -17,6 +17,7 @@ #include "lsdc_regs.h" #include "lsdc_i2c.h" +#include "lsdc_drv.h" /* * ls7a_gpio_i2c_set - set the state of a gpio pin, either high or low. @@ -24,10 +25,11 @@ */ static void ls7a_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int state) { + struct lsdc_device *ldev = to_lsdc(li2c->ddev); unsigned long flags; u8 val; - spin_lock_irqsave(&li2c->reglock, flags); + spin_lock_irqsave(&ldev->reglock, flags); if (state) { /* @@ -50,7 +52,7 @@ static void ls7a_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int state) writeb(val, li2c->dat_reg); } - spin_unlock_irqrestore(&li2c->reglock, flags); + spin_unlock_irqrestore(&ldev->reglock, flags); } /* @@ -59,10 +61,11 @@ static void ls7a_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int state) */ static int ls7a_gpio_i2c_get(struct lsdc_i2c * const li2c, int mask) { + struct lsdc_device *ldev = to_lsdc(li2c->ddev); unsigned long flags; u8 val; - spin_lock_irqsave(&li2c->reglock, flags); + spin_lock_irqsave(&ldev->reglock, flags); /* First, set this pin as input */ val = readb(li2c->dir_reg); @@ -72,7 +75,7 @@ static int ls7a_gpio_i2c_get(struct lsdc_i2c * const li2c, int mask) /* Then, get level state from this pin */ val = readb(li2c->dat_reg); - spin_unlock_irqrestore(&li2c->reglock, flags); + spin_unlock_irqrestore(&ldev->reglock, flags); return (val & mask) ? 1 : 0; } @@ -144,8 +147,6 @@ struct lsdc_i2c *lsdc_of_create_i2c_adapter(struct device *parent, if (!li2c) return ERR_PTR(-ENOMEM); - spin_lock_init(&li2c->reglock); - ret = of_property_read_u32(i2c_np, "loongson,sda", &sda); if (ret) { dev_err(parent, "No sda pin number provided\n"); @@ -248,8 +249,7 @@ struct lsdc_i2c *lsdc_create_i2c_chan(struct drm_device *ddev, li2c->scl = 0x08; } - spin_lock_init(&li2c->reglock); - + li2c->ddev = ddev; li2c->dir_reg = reg_base + LS7A_DC_GPIO_DIR_REG; li2c->dat_reg = reg_base + LS7A_DC_GPIO_DAT_REG; diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.h b/drivers/gpu/drm/loongson/lsdc_i2c.h index 62cbf2aaab2e..8fc1efc433d5 100644 --- a/drivers/gpu/drm/loongson/lsdc_i2c.h +++ b/drivers/gpu/drm/loongson/lsdc_i2c.h @@ -18,8 +18,9 @@ struct lsdc_i2c { struct i2c_adapter adapter; struct i2c_algo_bit_data bit; - /* @reglock: protects concurrent register access */ - spinlock_t reglock; + + struct drm_device *ddev; + void __iomem *dir_reg; void __iomem *dat_reg; /* pin bit mask */ diff --git a/drivers/gpu/drm/loongson/lsdc_output.c b/drivers/gpu/drm/loongson/lsdc_output.c index e8cefe6edd4d..ccc0a820ff8e 100644 --- a/drivers/gpu/drm/loongson/lsdc_output.c +++ b/drivers/gpu/drm/loongson/lsdc_output.c @@ -24,9 +24,7 @@ static int lsdc_get_modes(struct drm_connector *connector) { unsigned int num = 0; - struct lsdc_output *lop = drm_connector_to_lsdc_output(connector); - struct lsdc_i2c *li2c = lop->li2c; - struct i2c_adapter *ddc = &li2c->adapter; + struct i2c_adapter *ddc = connector->ddc; if (ddc) { struct edid *edid; @@ -51,26 +49,46 @@ static int lsdc_get_modes(struct drm_connector *connector) } static enum drm_connector_status -lsdc_connector_detect(struct drm_connector *connector, bool force) +ls7a1000_connector_detect(struct drm_connector *connector, bool force) { - struct lsdc_output *lop = drm_connector_to_lsdc_output(connector); - struct lsdc_i2c *li2c = lop->li2c; - struct i2c_adapter *ddc = &li2c->adapter; + struct i2c_adapter *ddc = connector->ddc; - if (ddc && drm_probe_ddc(ddc)) - return connector_status_connected; + if (ddc) { + if (drm_probe_ddc(ddc)) + return connector_status_connected; + else + return connector_status_disconnected; + } - if (connector->connector_type == DRM_MODE_CONNECTOR_VIRTUAL) - return connector_status_connected; + return connector_status_unknown; +} - if (connector->connector_type == DRM_MODE_CONNECTOR_DVIA || - connector->connector_type == DRM_MODE_CONNECTOR_DVID || - connector->connector_type == DRM_MODE_CONNECTOR_DVII) - return connector_status_disconnected; +static enum drm_connector_status +ls7a2000_connector_detect(struct drm_connector *connector, bool force) +{ + struct lsdc_display_pipe *dispipe = connector_to_display_pipe(connector); + struct drm_device *ddev = connector->dev; + struct lsdc_device *ldev = to_lsdc(ddev); + u32 val; + + val = lsdc_rreg32(ldev, LSDC_HDMI_HPD_STATUS_REG); + + if (dispipe->index == 0) { + if (val & HDMI0_HPD_FLAG) + return connector_status_connected; + + if (connector->ddc) { + if (drm_probe_ddc(connector->ddc)) + return connector_status_connected; + + return connector_status_disconnected; + } + } else if (dispipe->index == 1) { + if (val & HDMI1_HPD_FLAG) + return connector_status_connected; - if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) return connector_status_disconnected; + } return connector_status_unknown; } @@ -84,9 +102,19 @@ static const struct drm_connector_helper_funcs lsdc_connector_helpers = { .get_modes = lsdc_get_modes, }; -static const struct drm_connector_funcs lsdc_connector_funcs = { +static const struct drm_connector_funcs ls7a1000_connector_funcs = { .dpms = drm_helper_connector_dpms, - .detect = lsdc_connector_detect, + .detect = ls7a1000_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = lsdc_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_connector_funcs ls7a2000_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = ls7a2000_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = lsdc_connector_destroy, .reset = drm_atomic_helper_connector_reset, @@ -149,8 +177,8 @@ ls7a2000_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *ddev = encoder->dev; struct lsdc_device *ldev = to_lsdc(ddev); int clock = mode->clock; + int counter = 0; u32 val; - int counter; if (index == 0) { writel(0x0, ldev->reg_base + HDMI0_PLL_REG); @@ -219,12 +247,11 @@ static int lsdc_attach_bridges(struct lsdc_device *ldev, unsigned int i) { struct lsdc_display_pipe * const dispipe = &ldev->dispipe[i]; - struct drm_device *ddev = ldev->ddev; + struct drm_device *ddev = &ldev->ddev; struct drm_bridge *bridge; struct drm_panel *panel; struct drm_connector *connector; struct drm_encoder *encoder; - struct lsdc_output *output; int ret; ret = drm_of_find_panel_or_bridge(ports, i, 0, &panel, &bridge); @@ -237,11 +264,7 @@ static int lsdc_attach_bridges(struct lsdc_device *ldev, if (!bridge) return ret; - output = devm_kzalloc(ddev->dev, sizeof(*output), GFP_KERNEL); - if (!output) - return -ENOMEM; - - encoder = &output->encoder; + encoder = &dispipe->encoder; ret = drm_encoder_init(ddev, encoder, &lsdc_encoder_funcs, DRM_MODE_ENCODER_DPI, "encoder-%u", i); @@ -271,14 +294,12 @@ static int lsdc_attach_bridges(struct lsdc_device *ldev, drm_info(ddev, "bridge-%u attached to %s\n", i, encoder->name); - dispipe->output = output; - return 0; } int lsdc_attach_output(struct lsdc_device *ldev, uint32_t num_crtc) { - struct drm_device *ddev = ldev->ddev; + struct drm_device *ddev = &ldev->ddev; struct device_node *ports; struct lsdc_display_pipe *disp; unsigned int i; @@ -286,7 +307,7 @@ int lsdc_attach_output(struct lsdc_device *ldev, uint32_t num_crtc) ldev->num_output = 0; - ports = of_get_child_by_name(ldev->dev->of_node, "ports"); + ports = of_get_child_by_name(ddev->dev->of_node, "ports"); for (i = 0; i < num_crtc; i++) { struct drm_bridge *b; @@ -343,19 +364,23 @@ int lsdc_create_output(struct lsdc_device *ldev, { const struct lsdc_chip_desc * const descp = ldev->desc; struct lsdc_display_pipe * const dispipe = &ldev->dispipe[index]; - struct drm_device *ddev = ldev->ddev; + struct drm_encoder *encoder = &dispipe->encoder; + struct drm_connector *connector = &dispipe->connector; + struct drm_device *ddev = &ldev->ddev; int encoder_type = DRM_MODE_ENCODER_DPI; int connector_type = DRM_MODE_CONNECTOR_DPI; - struct lsdc_output *output; - struct drm_encoder *encoder; - struct drm_connector *connector; int ret; - output = devm_kzalloc(ddev->dev, sizeof(*output), GFP_KERNEL); - if (!output) - return -ENOMEM; - - encoder = &output->encoder; + if (descp->has_builtin_i2c) { + dispipe->li2c = lsdc_create_i2c_chan(ddev, ldev->reg_base, index); + if (IS_ERR(dispipe->li2c)) { + drm_err(ddev, "Failed to create i2c adapter\n"); + return PTR_ERR(dispipe->li2c); + } + } else { + drm_warn(ddev, "output-%u don't has ddc\n", index); + dispipe->li2c = NULL; + } if (descp->chip == LSDC_CHIP_7A2000) { encoder_type = DRM_MODE_ENCODER_TMDS; @@ -370,32 +395,31 @@ int lsdc_create_output(struct lsdc_device *ldev, return ret; } + encoder->possible_crtcs = BIT(index); + if (descp->chip == LSDC_CHIP_7A2000) drm_encoder_helper_add(encoder, &ls7a2000_hdmi_encoder_helper_funcs); - encoder->possible_crtcs = BIT(index); - - if (descp->has_builtin_i2c) { - output->li2c = lsdc_create_i2c_chan(ddev, ldev->reg_base, index); - if (IS_ERR(output->li2c)) { - drm_err(ddev, "Failed to create i2c adapter\n"); - return PTR_ERR(output->li2c); + if (descp->chip == LSDC_CHIP_7A2000) { + ret = drm_connector_init_with_ddc(ddev, + connector, + &ls7a2000_connector_funcs, + connector_type, + &dispipe->li2c->adapter); + if (ret) { + drm_err(ddev, "Init connector%d failed\n", index); + return ret; } } else { - drm_warn(ddev, "output-%u don't has ddc\n", index); - output->li2c = NULL; - } - - connector = &output->connector; - - ret = drm_connector_init_with_ddc(ddev, - connector, - &lsdc_connector_funcs, - connector_type, - &output->li2c->adapter); - if (ret) { - drm_err(ddev, "Init connector%d failed\n", index); - return ret; + ret = drm_connector_init_with_ddc(ddev, + connector, + &ls7a1000_connector_funcs, + connector_type, + &dispipe->li2c->adapter); + if (ret) { + drm_err(ddev, "Init connector%d failed\n", index); + return ret; + } } drm_connector_helper_add(connector, &lsdc_connector_helpers); @@ -405,7 +429,7 @@ int lsdc_create_output(struct lsdc_device *ldev, drm_connector_attach_encoder(connector, encoder); dispipe->available = true; - dispipe->output = output; + ldev->num_output++; return 0; diff --git a/drivers/gpu/drm/loongson/lsdc_pci_drv.c b/drivers/gpu/drm/loongson/lsdc_pci_drv.c index e202da6621bc..127299813b11 100644 --- a/drivers/gpu/drm/loongson/lsdc_pci_drv.c +++ b/drivers/gpu/drm/loongson/lsdc_pci_drv.c @@ -9,344 +9,8 @@ * Sui Jingfeng */ -#include -#include -#include -#include -#include -#include "lsdc_drv.h" -#include "lsdc_i2c.h" -static int lsdc_use_vram_helper = -1; -MODULE_PARM_DESC(use_vram_helper, "Using vram helper based driver(0 = disabled)"); -module_param_named(use_vram_helper, lsdc_use_vram_helper, int, 0644); -static int lsdc_gamma = -1; -MODULE_PARM_DESC(gamma, "enable gamma (-1 = disabled (default), >0 = enabled)"); -module_param_named(gamma, lsdc_gamma, int, 0644); -static int lsdc_relax_alignment = -1; -MODULE_PARM_DESC(relax_alignment, - "relax crtc stride alignment (-1 = disabled (default), >0 = enabled)"); -module_param_named(relax_alignment, lsdc_relax_alignment, int, 0644); - - -static struct platform_device * -lsdc_create_platform_device(const char *name, - struct device *parent, - const struct lsdc_chip_desc *descp, - struct resource *res) -{ - struct device *dev; - struct platform_device *pdev; - int ret; - - pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); - if (!pdev) { - dev_err(parent, "can not create platform device\n"); - return ERR_PTR(-ENOMEM); - } - - dev_info(parent, "platform device %s created\n", name); - - dev = &pdev->dev; - dev->parent = parent; - - if (descp) { - ret = platform_device_add_data(pdev, descp, sizeof(*descp)); - if (ret) { - dev_err(parent, "add platform data failed: %d\n", ret); - goto ERROR_RET; - } - } - - if (res) { - ret = platform_device_add_resources(pdev, res, 1); - if (ret) { - dev_err(parent, "add platform resources failed: %d\n", ret); - goto ERROR_RET; - } - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(parent, "add platform device failed: %d\n", ret); - goto ERROR_RET; - } - - return pdev; - -ERROR_RET: - platform_device_put(pdev); - return ERR_PTR(ret); -} - -static int lsdc_vram_init(struct lsdc_device *ldev) -{ - const struct lsdc_chip_desc * const descp = ldev->desc; - struct pci_dev *gpu; - resource_size_t base, size; - - if (descp->chip == LSDC_CHIP_7A2000) { - /* BAR 2 of LS7A2000's GPU contain VRAM */ - gpu = pci_get_device(PCI_VENDOR_ID_LOONGSON, 0x7A25, NULL); - } else if (descp->chip == LSDC_CHIP_7A1000) { - /* BAR 2 of LS7A1000's GPU(GC1000) contain VRAM */ - gpu = pci_get_device(PCI_VENDOR_ID_LOONGSON, 0x7A15, NULL); - } else { - dev_err(ldev->dev, "Unknown chip, the driver need update\n"); - return -ENOENT; - } - - if (IS_ERR_OR_NULL(gpu)) { - dev_err(ldev->dev, "Can not get VRAM\n"); - return -ENOENT; - } - - base = pci_resource_start(gpu, 2); - size = pci_resource_len(gpu, 2); - - ldev->vram_base = base; - ldev->vram_size = size; - - dev_info(ldev->dev, "vram start: 0x%llx, size: %uMB\n", - (u64)base, (u32)(size >> 20)); - - return 0; -} - -static void lsdc_of_probe(struct lsdc_device *ldev, struct device_node *np) -{ - struct device_node *ports; - - if (!np) { - ldev->has_dt = false; - ldev->has_ports_node = false; - dev_info(ldev->dev, "don't has DT support\n"); - return; - } - - ports = of_get_child_by_name(np, "ports"); - ldev->has_ports_node = ports ? true : false; - of_node_put(ports); -} - -static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct device *dev = &pdev->dev; - const struct lsdc_chip_desc *descp; - struct lsdc_device *ldev; - int ret; - - descp = lsdc_detect_chip(pdev, ent); - if (!descp) { - dev_info(dev, "unknown dc ip core, abort\n"); - return -ENOENT; - } - - ldev = devm_kzalloc(dev, sizeof(*ldev), GFP_KERNEL); - if (IS_ERR(ldev)) - return PTR_ERR(ldev); - - ldev->desc = descp; - ldev->dev = dev; - - if (lsdc_use_vram_helper > 0) - ldev->use_vram_helper = true; - else if ((lsdc_use_vram_helper < 0) && descp->has_vram) - ldev->use_vram_helper = true; - else - ldev->use_vram_helper = false; - - if (!descp->broken_gamma) - ldev->enable_gamma = true; - else - ldev->enable_gamma = lsdc_gamma > 0 ? true : false; - - ldev->relax_alignment = lsdc_relax_alignment > 0 ? true : false; - - lsdc_of_probe(ldev, dev->of_node); - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - /* BAR 0 contains registers */ - ldev->reg_base = devm_ioremap_resource(dev, &pdev->resource[0]); - if (IS_ERR(ldev->reg_base)) - return PTR_ERR(ldev->reg_base); - - /* Create GPIO emulated i2c driver as early as possible */ - if (descp->has_builtin_i2c && ldev->has_ports_node) { - struct device_node *i2c_node; - - for_each_compatible_node(i2c_node, NULL, "loongson,gpio-i2c") { - if (!of_device_is_available(i2c_node)) - continue; - - lsdc_of_create_i2c_adapter(dev, ldev->reg_base, i2c_node); - } - } - - if (ldev->has_dt) { - /* Get the optional framebuffer memory resource */ - ret = of_reserved_mem_device_init(dev); - if (ret && (ret != -ENODEV)) - return ret; - } - - if (descp->has_vram && ldev->use_vram_helper) { - ret = lsdc_vram_init(ldev); - if (ret) { - dev_err(dev, "VRAM is unavailable\n"); - ldev->use_vram_helper = false; - } - } - - ldev->irq = pdev->irq; - - dev_set_drvdata(dev, ldev); - - if (descp->has_vram && ldev->use_vram_helper) { - struct resource res; - - memset(&res, 0, sizeof(res)); - res.flags = IORESOURCE_MEM; - res.name = "LS7A_VRAM"; - res.start = ldev->vram_base; - res.end = ldev->vram_size; - } - - ldev->dc = lsdc_create_platform_device("lsdc", dev, descp, NULL); - if (IS_ERR(ldev->dc)) - return PTR_ERR(ldev->dc); - - return platform_driver_register(&lsdc_platform_driver); -} - -static void lsdc_pci_remove(struct pci_dev *pdev) -{ - struct lsdc_device *ldev = pci_get_drvdata(pdev); - - platform_device_unregister(ldev->dc); - - pci_set_drvdata(pdev, NULL); - - pci_clear_master(pdev); - - pci_release_regions(pdev); -} - -static int lsdc_drm_suspend(struct device *dev) -{ - struct lsdc_device *ldev = dev_get_drvdata(dev); - - return drm_mode_config_helper_suspend(ldev->ddev); -} - -static int lsdc_drm_resume(struct device *dev) -{ - struct lsdc_device *ldev = dev_get_drvdata(dev); - - return drm_mode_config_helper_resume(ldev->ddev); -} - -static int lsdc_pm_freeze(struct device *dev) -{ - return lsdc_drm_suspend(dev); -} - -static int lsdc_pm_thaw(struct device *dev) -{ - return lsdc_drm_resume(dev); -} - -static int lsdc_pm_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int error; - - error = lsdc_pm_freeze(dev); - if (error) - return error; - - pci_save_state(pdev); - /* Shut down the device */ - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -static int lsdc_pm_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - - if (pcim_enable_device(pdev)) - return -EIO; - - pci_set_power_state(pdev, PCI_D0); - - pci_restore_state(pdev); - - return lsdc_pm_thaw(dev); -} - -static const struct dev_pm_ops lsdc_pm_ops = { - .suspend = lsdc_pm_suspend, - .resume = lsdc_pm_resume, - .freeze = lsdc_pm_freeze, - .thaw = lsdc_pm_thaw, - .poweroff = lsdc_pm_freeze, - .restore = lsdc_pm_resume, -}; - -static const struct pci_device_id lsdc_pciid_list[] = { - {PCI_VENDOR_ID_LOONGSON, 0x7a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)LSDC_CHIP_7A1000}, - {PCI_VENDOR_ID_LOONGSON, 0x7a36, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)LSDC_CHIP_7A2000}, - {0, 0, 0, 0, 0, 0, 0} -}; - -static struct pci_driver lsdc_pci_driver = { - .name = DRIVER_NAME, - .id_table = lsdc_pciid_list, - .probe = lsdc_pci_probe, - .remove = lsdc_pci_remove, - .driver.pm = &lsdc_pm_ops, -}; - -static int __init lsdc_drm_init(void) -{ - struct pci_dev *pdev = NULL; - - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) { - /* - * Multiple video card workaround - * - * This integrated video card will always be selected as - * default boot device by vgaarb subsystem. - */ - if (pdev->vendor != PCI_VENDOR_ID_LOONGSON) { - pr_info("Discrete graphic card detected, abort\n"); - return 0; - } - } - - return pci_register_driver(&lsdc_pci_driver); -} -module_init(lsdc_drm_init); - -static void __exit lsdc_drm_exit(void) -{ - pci_unregister_driver(&lsdc_pci_driver); -} -module_exit(lsdc_drm_exit); - -MODULE_DEVICE_TABLE(pci, lsdc_pciid_list); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/loongson/lsdc_plane.c b/drivers/gpu/drm/loongson/lsdc_plane.c index 6f65c9fd687e..085347ec804e 100644 --- a/drivers/gpu/drm/loongson/lsdc_plane.c +++ b/drivers/gpu/drm/loongson/lsdc_plane.c @@ -70,54 +70,32 @@ static void lsdc_update_fb_format(struct lsdc_device *ldev, } static void lsdc_update_fb_start_addr(struct lsdc_device *ldev, - struct drm_crtc *crtc, - u64 paddr) + unsigned int index, + u64 fb_addr) { - unsigned int index = drm_crtc_index(crtc); - u32 lo32_addr_reg; - u32 hi32_addr_reg; - u32 cfg_reg; - u32 val; + u32 lo = fb_addr & 0xFFFFFFFF; + u32 hi = (fb_addr >> 32) & 0xFF; + u32 cfg; - /* - * Find which framebuffer address register should update. - * if FB_ADDR0_REG is in using, we write the addr to FB_ADDR1_REG, - * if FB_ADDR1_REG is in using, we write the addr to FB_ADDR0_REG - */ if (index == 0) { - /* CRTC0 */ - val = readl(ldev->reg_base + LSDC_CRTC0_CFG_REG); - - cfg_reg = LSDC_CRTC0_CFG_REG; - hi32_addr_reg = LSDC_CRTC0_FB_HI_ADDR_REG; - - if (val & CFG_FB_IDX_BIT) - lo32_addr_reg = LSDC_CRTC0_FB_ADDR0_REG; - else - lo32_addr_reg = LSDC_CRTC0_FB_ADDR1_REG; + cfg = lsdc_crtc_rreg32(ldev, LSDC_CRTC0_CFG_REG, index); + if (cfg & BIT(9)) { + lsdc_wreg32(ldev, LSDC_CRTC0_FB1_LO_ADDR_REG, lo); + lsdc_wreg32(ldev, LSDC_CRTC0_FB1_HI_ADDR_REG, hi); + } else { + lsdc_wreg32(ldev, LSDC_CRTC0_FB0_LO_ADDR_REG, lo); + lsdc_wreg32(ldev, LSDC_CRTC0_FB0_HI_ADDR_REG, hi); + } } else if (index == 1) { - /* CRTC1 */ - val = readl(ldev->reg_base + LSDC_CRTC1_CFG_REG); - - cfg_reg = LSDC_CRTC1_CFG_REG; - hi32_addr_reg = LSDC_CRTC1_FB_HI_ADDR_REG; - - if (val & CFG_FB_IDX_BIT) - lo32_addr_reg = LSDC_CRTC1_FB_ADDR0_REG; - else - lo32_addr_reg = LSDC_CRTC1_FB_ADDR1_REG; + cfg = lsdc_crtc_rreg32(ldev, LSDC_CRTC1_CFG_REG, index); + if (cfg & BIT(9)) { + lsdc_wreg32(ldev, LSDC_CRTC1_FB1_LO_ADDR_REG, lo); + lsdc_wreg32(ldev, LSDC_CRTC1_FB1_HI_ADDR_REG, hi); + } else { + lsdc_wreg32(ldev, LSDC_CRTC1_FB0_LO_ADDR_REG, lo); + lsdc_wreg32(ldev, LSDC_CRTC1_FB0_HI_ADDR_REG, hi); + } } - - drm_dbg(ldev->ddev, "crtc%u scantout from 0x%llx\n", index, paddr); - - /* The bridge's bus width is 40 */ - writel(paddr, ldev->reg_base + lo32_addr_reg); - writel((paddr >> 32) & 0xFF, ldev->reg_base + hi32_addr_reg); - /* - * Then, we triger the fb switch, the switch of the framebuffer - * to be scanout will complete at the next vblank. - */ - writel(val | CFG_PAGE_FLIP_BIT, ldev->reg_base + cfg_reg); } static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb, @@ -176,7 +154,7 @@ static void lsdc_update_stride(struct lsdc_device *ldev, else if (index == 1) writel(stride, ldev->reg_base + LSDC_CRTC1_STRIDE_REG); - drm_dbg(ldev->ddev, "update stride to %u\n", stride); + drm_dbg(&ldev->ddev, "update stride to %u\n", stride); } static void lsdc_primary_plane_atomic_update(struct drm_plane *plane, @@ -204,7 +182,7 @@ static void lsdc_primary_plane_atomic_update(struct drm_plane *plane, fb_addr = obj->paddr + fb_offset; } - lsdc_update_fb_start_addr(ldev, crtc, fb_addr); + lsdc_update_fb_start_addr(ldev, drm_crtc_index(crtc), fb_addr); lsdc_update_stride(ldev, crtc, fb->pitches[0]); @@ -276,7 +254,7 @@ static int lsdc_cursor_atomic_check(struct drm_plane *plane, static void lsdc_cursor_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_plane_state) { - struct lsdc_display_pipe * const dispipe = lsdc_cursor_to_dispipe(plane); + struct lsdc_display_pipe * const dispipe = cursor_to_display_pipe(plane); struct drm_device *ddev = plane->dev; struct lsdc_device *ldev = to_lsdc(ddev); const struct lsdc_chip_desc * const descp = ldev->desc; @@ -357,7 +335,7 @@ static void lsdc_cursor_atomic_update(struct drm_plane *plane, static void lsdc_cursor_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - const struct lsdc_display_pipe * const dispipe = lsdc_cursor_to_dispipe(plane); + const struct lsdc_display_pipe * const dispipe = cursor_to_display_pipe(plane); struct drm_device *ddev = plane->dev; struct lsdc_device *ldev = to_lsdc(ddev); const struct lsdc_chip_desc * const descp = ldev->desc; @@ -423,7 +401,7 @@ int lsdc_plane_init(struct lsdc_device *ldev, enum drm_plane_type type, unsigned int index) { - struct drm_device *ddev = ldev->ddev; + struct drm_device *ddev = &ldev->ddev; int zpos = lsdc_plane_get_default_zpos(type); unsigned int format_count; const u32 *formats; diff --git a/drivers/gpu/drm/loongson/lsdc_regs.h b/drivers/gpu/drm/loongson/lsdc_regs.h index ffa6285530d7..00ccac2601cd 100644 --- a/drivers/gpu/drm/loongson/lsdc_regs.h +++ b/drivers/gpu/drm/loongson/lsdc_regs.h @@ -77,9 +77,8 @@ enum lsdc_pixel_format { /******** CRTC0 & DVO0 ********/ #define LSDC_CRTC0_CFG_REG 0x1240 -#define LSDC_CRTC0_FB_ADDR0_REG 0x1260 -#define LSDC_CRTC0_FB_ADDR1_REG 0x1580 -#define LSDC_CRTC0_FB_HI_ADDR_REG 0x15A0 +#define LSDC_CRTC0_FB0_LO_ADDR_REG 0x1260 +#define LSDC_CRTC0_FB0_HI_ADDR_REG 0x15A0 #define LSDC_CRTC0_STRIDE_REG 0x1280 #define LSDC_CRTC0_FB_ORIGIN_REG 0x1300 #define LSDC_CRTC0_HDISPLAY_REG 0x1400 @@ -88,12 +87,13 @@ enum lsdc_pixel_format { #define LSDC_CRTC0_VSYNC_REG 0x14A0 #define LSDC_CRTC0_GAMMA_INDEX_REG 0x14E0 #define LSDC_CRTC0_GAMMA_DATA_REG 0x1500 +#define LSDC_CRTC0_FB1_LO_ADDR_REG 0x1580 +#define LSDC_CRTC0_FB1_HI_ADDR_REG 0x15C0 /******** CTRC1 & DVO1 ********/ #define LSDC_CRTC1_CFG_REG 0x1250 -#define LSDC_CRTC1_FB_ADDR0_REG 0x1270 -#define LSDC_CRTC1_FB_ADDR1_REG 0x1590 -#define LSDC_CRTC1_FB_HI_ADDR_REG 0x15C0 +#define LSDC_CRTC1_FB0_LO_ADDR_REG 0x1270 +#define LSDC_CRTC1_FB0_HI_ADDR_REG 0x15B0 #define LSDC_CRTC1_STRIDE_REG 0x1290 #define LSDC_CRTC1_FB_ORIGIN_REG 0x1310 #define LSDC_CRTC1_HDISPLAY_REG 0x1410 @@ -102,8 +102,17 @@ enum lsdc_pixel_format { #define LSDC_CRTC1_VSYNC_REG 0x14B0 #define LSDC_CRTC1_GAMMA_INDEX_REG 0x14F0 #define LSDC_CRTC1_GAMMA_DATA_REG 0x1510 +#define LSDC_CRTC1_FB1_LO_ADDR_REG 0x1590 +#define LSDC_CRTC1_FB1_HI_ADDR_REG 0x15D0 -#define LSDC_REGS_OFFSET 0x0010 +/* + * In gross, LSDC_CRTC1_XXX_REG - LSDC_CRTC0_XXX_REG = 0x10, but not all of + * the registers obey this rule, LSDC_CURSORx_XXX_REG just don't honor this. + * This is the root cause we can't untangle the code by manpulating offset + * of the register access simply. Our hardware engineers are lack experiance + * when they design this... + */ +#define CRTC_PIPE_OFFSET 0x10 /* * Hardware cursor @@ -249,4 +258,11 @@ enum lsdc_pixel_format { #define DMA_STEP_64_BYTE (2 << 16) #define DMA_STEP_32_BYTE (3 << 16) +/* LS7A2000/LS2K2000 has hpd status reg, while the two hdmi's status + * located at the one register again. + */ +#define LSDC_HDMI_HPD_STATUS_REG 0x1BA0 +#define HDMI0_HPD_FLAG BIT(0) +#define HDMI1_HPD_FLAG BIT(1) + #endif -- GitLab