提交 07b9d70b 编写于 作者: S Sui Jingfeng 提交者: Hongchen Zhang

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: NSui Jingfeng <15330273260@189.cn>
Change-Id: I7934f66c8993b4d9d77a9fe04438849e1f6191ac
上级 543f2481
......@@ -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
......
......@@ -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);
......
......@@ -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),
......
......@@ -11,6 +11,10 @@
#include <linux/pci.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <drm/drm_vblank.h>
#include <drm/drm_fb_helper.h>
......@@ -20,11 +24,26 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_modeset_helper.h>
#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");
......@@ -21,6 +21,7 @@
#include <drm/drm_atomic.h>
#include "lsdc_pll.h"
#include "lsdc_regs.h"
#define DRIVER_AUTHOR "Sui Jingfeng <suijingfeng@loongson.cn>"
#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
......@@ -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;
......
......@@ -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 */
......
......@@ -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;
......
......@@ -9,344 +9,8 @@
* Sui Jingfeng <suijingfeng@loongson.cn>
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <drm/drm_modeset_helper.h>
#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");
......@@ -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;
......
......@@ -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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册