Subject: [path v2 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver

From: [email-masked] (Rongrong Zou)
Date: Mon, 30 May 2016 20:51:40 +0800

Sorry, forgot to add daniel at ffwll.ch to sendto list.

? 2016/5/30 20:09, Rongrong Zou ??:
> Hi Daniel,
> Thanks for reveiwing!
>
> ? 2016/5/30 17:03, Daniel Vetter ??:
>> On Sun, May 29, 2016 at 05:40:49PM +0800, Rongrong Zou wrote:
>>> Add DRM master driver for Hisilicon Hibmc SoC which used for
>>> Out-of-band management. Blow is the general hardware connection,
>>> both the Hibmc and the host CPU are on the same mother board.
>>>
>>> +----------+       +----------+
>>> |          | PCIe  |  Hibmc   |
>>> |host CPU( |<----->| display  |
>>> |arm64,x86)|       |subsystem |
>>> +----------+       +----------+
>>>
>>> Signed-off-by: Rongrong Zou <[email-masked]>
>>> Signed-off-by: Jianhua Li <[email-masked]>
>>> ---
>>>   drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>>   drivers/gpu/drm/hisilicon/Makefile                |   3 +-
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig           |  13 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 307 ++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  39 +++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  91 +++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 ++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 214 +++++++++++++++
>>>   9 files changed, 699 insertions(+), 1 deletion(-)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
>>> index 558c61b..2fd2724 100644
>>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>>> @@ -2,4 +2,5 @@
>>>   # hisilicon drm device configuration.
>>>   # Please keep this list sorted alphabetically
>>>
>>> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>>>   source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
>>> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
>>> index e3f6d49..4d7185c 100644
>>> --- a/drivers/gpu/drm/hisilicon/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>>> @@ -2,4 +2,5 @@
>>>   # Makefile for hisilicon drm drivers.
>>>   # Please keep this list sorted alphabetically
>>>
>>> -obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
>>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>>> +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
>>> \ No newline at end of file
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> new file mode 100644
>>> index 0000000..1e7810d
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> @@ -0,0 +1,13 @@
>>> +config DRM_HISI_HIBMC
>>> +    tristate "DRM Support for Hisilicon Hibmc"
>>> +    depends on DRM && PCI
>>> +    select DRM_KMS_HELPER
>>> +    select DRM_KMS_FB_HELPER
>>> +    select DRM_GEM_CMA_HELPER
>>> +    select DRM_KMS_CMA_HELPER
>>> +    select FB_SYS_FILLRECT
>>> +    select FB_SYS_COPYAREA
>>> +    select FB_SYS_IMAGEBLIT
>>> +    help
>>> +      Choose this option if you have a Hisilicon Hibmc soc chipset.
>>> +      If M is selected the module will be called hibmc-drm.
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> new file mode 100644
>>> index 0000000..533f9ed
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -0,0 +1,4 @@
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>>> +
>>> +obj-$(CONFIG_DRM_HISI_HIBMC)    +=hibmc-drm.o
>>> +#obj-y    += hibmc-drm.o
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> new file mode 100644
>>> index 0000000..7eaacd8
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -0,0 +1,307 @@
>>> +/* Hisilicon Hibmc SoC drm driver
>>> + *
>>> + * Based on the bochs drm driver.
>>> + *
>>> + * Copyright (c) 2016 Huawei Limited.
>>> + *
>>> + * Author:
>>> + *    Rongrong Zou <zourongrong@huawei>
>>> + *    Rongrong Zou <[email-masked]>
>>> + *    Jianhua Li <[email-masked]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/console.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_fb_helper.h>
>>> +#include <drm/drm_gem_cma_helper.h>
>>> +#include <drm/drmP.h>
>>> +
>>> +#include "hibmc_drm_drv.h"
>>> +#include "hibmc_drm_regs.h"
>>> +#include "hibmc_drm_power.h"
>>> +
>>> +static const struct file_operations hibmc_fops = {
>>> +    .owner        = THIS_MODULE,
>>> +    .open        = drm_open,
>>> +    .release    = drm_release,
>>> +    .unlocked_ioctl    = drm_ioctl,
>>> +#ifdef CONFIG_COMPAT
>>> +    .compat_ioctl    = drm_compat_ioctl,
>>> +#endif
>>> +    .poll        = drm_poll,
>>> +    .read        = drm_read,
>>> +    .llseek        = no_llseek,
>>> +};
>>> +
>>> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>>> +{
>>> +}
>>> +
>>> +static struct drm_driver hibmc_driver = {
>>> +    .driver_features    = DRIVER_GEM | DRIVER_MODESET,
>>> +    .fops            = &hibmc_fops,
>>> +    .name            = "hibmc",
>>> +    .desc            = "hibmc drm driver",
>>> +    .major            = 1,
>>> +    .minor            = 0,
>>> +    .get_vblank_counter = drm_vblank_no_hw_counter,
>>> +    .enable_vblank        = hibmc_enable_vblank,
>>> +    .disable_vblank    = hibmc_disable_vblank,
>>> +    .gem_free_object        = drm_gem_cma_free_object,
>>
>> gem_free_object_unlocked pls.
>
> Applied, thanks.
>
>>
>>> +    .gem_vm_ops        = &drm_gem_cma_vm_ops,
>>> +    .dumb_create            = drm_gem_cma_dumb_create,
>>> +    .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
>>> +    .dumb_destroy           = drm_gem_dumb_destroy,
>>> +};
>>> +
>>> +static int hibmc_pm_suspend(struct device *dev)
>>> +{
>>> +    struct pci_dev *pdev = to_pci_dev(dev);
>>> +    struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>> +
>>> +    drm_kms_helper_poll_disable(drm_dev);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int hibmc_pm_resume(struct device *dev)
>>> +{
>>> +    struct pci_dev *pdev = to_pci_dev(dev);
>>> +    struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>> +
>>> +    drm_helper_resume_force_mode(drm_dev);
>>> +    drm_kms_helper_poll_enable(drm_dev);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static const struct dev_pm_ops hibmc_pm_ops = {
>>> +    SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
>>> +                hibmc_pm_resume)
>>> +};
>>> +
>>> +static const struct drm_mode_config_funcs mode_config_funcs = {
>>> +    .atomic_check = drm_atomic_helper_check,
>>> +    .atomic_commit = drm_atomic_helper_commit,
>>
>> So how exactly does nonblocking commit work for you? Please run the igt
>> validation suit on your new driver, a bunch of collabora engineers are
>> working hard to make it run on non-intel drivers too. Ping Tomeu and
>> Robert Foss for more info on this please.
>
> OK, I should learn igt validation suit and test the new driver.
> I tested the driver with tools such as fbtest before. Thanks.
>
>>
>> Lucky for you I'm working on generic nonblocking support in the atomic
>> helpers, patches are on the mailing list.
>>
>
> It's nice, thanks. :)
>
>>> +};
>>> +
>>> +
>>> +static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>>> +{
>>> +    unsigned int reg;
>>> +
>>> +    /* On hardware reset, power mode 0 is default. */
>>> +    hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>>> +
>>> +    /* Enable display power gate & LOCALMEM power gate*/
>>> +    reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +    reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +    reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +    reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>>> +    reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>>> +
>>> +    hibmc_set_current_gate(hidev, reg);
>>> +
>>> +    /* Reset the memory controller. If the memory controller
>>> +     * is not reset in chip,the system might hang when sw accesses
>>> +     * the memory.The memory should be resetted after
>>> +     * changing the MXCLK.
>>> +     */
>>> +    reg = readl(hidev->mmio + HIBMC_MISC_CTRL);
>>> +    reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>>> +    reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
>>> +    writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>>> +
>>> +    reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>>> +    reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
>>> +
>>> +    writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>>> +
>>> +    /* We can add more initialization as needed. */
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int hibmc_hw_map(struct hibmc_drm_device *hidev)
>>> +{
>>> +    struct drm_device *dev = hidev->dev;
>>> +    struct pci_dev *pdev = dev->pdev;
>>> +    resource_size_t addr, size, ioaddr, iosize;
>>> +
>>> +    ioaddr = pci_resource_start(pdev, 1);
>>> +    iosize = MB(2);
>>> +
>>> +    hidev->mmio = ioremap_nocache(ioaddr, iosize);
>>> +
>>> +    if (!hidev->mmio) {
>>> +        DRM_ERROR("Cannot map mmio region\n");
>>> +        return -ENOMEM;
>>> +    }
>>> +
>>> +    addr = pci_resource_start(pdev, 0);
>>> +    size = MB(16);
>>> +
>>> +    hidev->fb_map = ioremap(addr, size);
>>> +    if (!hidev->fb_map) {
>>> +        DRM_ERROR("Cannot map framebuffer\n");
>>> +        return -ENOMEM;
>>> +    }
>>> +    hidev->fb_base = addr;
>>> +    hidev->fb_size = size;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
>>> +{
>>> +    if (hidev->mmio)
>>> +        iounmap(hidev->mmio);
>>> +    if (hidev->fb_map)
>>> +        iounmap(hidev->fb_map);
>>> +}
>>> +
>>> +static int hibmc_hw_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +    int ret;
>>> +
>>> +    ret = hibmc_hw_map(hidev);
>>> +    if (ret)
>>> +        return ret;
>>> +
>>> +    hibmc_hw_config(hidev);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int hibmc_unload(struct drm_device *dev)
>>> +{
>>> +    struct hibmc_drm_device *hidev = dev->dev_private;
>>> +
>>> +    hibmc_hw_fini(hidev);
>>> +    dev->dev_private = NULL;
>>> +    return 0;
>>> +}
>>> +
>>> +static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>> +{
>>> +    struct hibmc_drm_device *hidev;
>>> +    int ret;
>>> +
>>> +    hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
>>> +    if (!hidev)
>>> +        return -ENOMEM;
>>> +    dev->dev_private = hidev;
>>> +    hidev->dev = dev;
>>> +
>>> +    ret = hibmc_hw_init(hidev);
>>> +    if (ret)
>>> +        goto err;
>>> +
>>> +
>>> +    ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>>> +    if (ret) {
>>> +        DRM_ERROR("failed to initialize vblank.\n");
>>> +        return ret;
>>> +    }
>>> +    /* reset all the states of crtc/plane/encoder/connector */
>>> +    drm_mode_config_reset(dev);
>>> +
>>> +    return 0;
>>> +
>>> +err:
>>> +    hibmc_unload(dev);
>>> +    DRM_ERROR("failed to initialize drm driver.\n");
>>> +    return ret;
>>> +}
>>> +
>>> +
>>> +static int hibmc_pci_probe(struct pci_dev *pdev,
>>> +               const struct pci_device_id *ent)
>>> +{
>>> +    struct drm_device *dev;
>>> +    int ret;
>>> +
>>> +    dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
>>> +    if (!dev)
>>> +        return -ENOMEM;
>>> +
>>> +    dev->pdev = pdev;
>>> +    pci_set_drvdata(pdev, dev);
>>> +
>>> +    ret = pci_enable_device(pdev);
>>> +    if (ret)
>>> +        goto err_free;
>>> +
>>> +    ret = hibmc_load(dev, 0);
>>> +    if (ret)
>>> +        goto err_disable;
>>> +
>>> +    ret = drm_dev_register(dev, 0);
>>> +    if (ret)
>>> +        goto err_unload;
>>> +
>>> +    return 0;
>>> +
>>> +err_unload:
>>> +    hibmc_unload(dev);
>>> +err_disable:
>>> +    pci_disable_device(pdev);
>>> +err_free:
>>> +    drm_dev_unref(dev);
>>> +
>>> +    return ret;
>>> +}
>>> +
>>> +static void hibmc_pci_remove(struct pci_dev *pdev)
>>> +{
>>> +    struct drm_device *dev = pci_get_drvdata(pdev);
>>> +
>>> +    drm_dev_unregister(dev);
>>> +    hibmc_unload(dev);
>>> +    drm_dev_unref(dev);
>>> +}
>>> +
>>> +static struct pci_device_id hibmc_pci_table[] = {
>>> +    {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
>>> +    {0,}
>>> +};
>>> +
>>> +static struct pci_driver hibmc_pci_driver = {
>>> +    .name =        "hibmc-drm",
>>> +    .id_table =    hibmc_pci_table,
>>> +    .probe =    hibmc_pci_probe,
>>> +    .remove =    hibmc_pci_remove,
>>> +    .driver.pm =    &hibmc_pm_ops,
>>> +};
>>> +
>>> +static int __init hibmc_init(void)
>>> +{
>>> +    return pci_register_driver(&hibmc_pci_driver);
>>> +}
>>> +
>>> +static void __exit hibmc_exit(void)
>>> +{
>>> +    return pci_unregister_driver(&hibmc_pci_driver);
>>> +}
>>> +
>>> +module_init(hibmc_init);
>>> +module_exit(hibmc_exit);
>>> +
>>> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
>>> +MODULE_AUTHOR("RongrongZou <[email-masked]>");
>>> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
>>> +MODULE_LICENSE("GPL v2");
>>> +
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> new file mode 100644
>>> index 0000000..a072ea9
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -0,0 +1,39 @@
>>> +/* Hisilicon Hibmc SoC drm driver
>>> + *
>>> + * Based on the bochs drm driver.
>>> + *
>>> + * Copyright (c) 2016 Huawei Limited.
>>> + *
>>> + * Author:
>>> + *    Rongrong Zou <zourongrong@huawei>
>>> + *    Rongrong Zou <[email-masked]>
>>> + *    Jianhua Li <[email-masked]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifndef HIBMC_DRM_DRV_H
>>> +#define HIBMC_DRM_DRV_H
>>> +
>>> +#include <drm/drmP.h>
>>> +#include <drm/drm_fb_helper.h>
>>> +#include <drm/drm_gem_cma_helper.h>
>>> +
>>> +struct hibmc_drm_device {
>>> +    /* hw */
>>> +    void __iomem   *mmio;
>>> +    void __iomem   *fb_map;
>>> +    unsigned long  fb_base;
>>> +    unsigned long  fb_size;
>>> +
>>> +    /* drm */
>>> +    struct drm_device  *dev;
>>> +    bool mode_config_initialized;
>>> +};
>>> +
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>>> new file mode 100644
>>> index 0000000..673be10
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>>> @@ -0,0 +1,91 @@
>>> +/* Hisilicon Hibmc SoC drm driver
>>> + *
>>> + * Based on the bochs drm driver.
>>> + *
>>> + * Copyright (c) 2016 Huawei Limited.
>>> + *
>>> + * Author:
>>> + *    Rongrong Zou <zourongrong@huawei>
>>> + *    Rongrong Zou <[email-masked]>
>>> + *    Jianhua Li <[email-masked]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#include <linux/io.h>
>>> +#include <drm/drmP.h>
>>> +#include <drm/drm_fb_helper.h>
>>> +#include "hibmc_drm_drv.h"
>>> +#include "hibmc_drm_regs.h"
>>> +
>>> +/*
>>> + * It can operate in one of three modes: 0, 1 or Sleep.
>>> + */
>>> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>>> +                 unsigned int power_mode)
>>> +{
>>> +    unsigned int control_value = 0;
>>> +    void __iomem   *mmio = hidev->mmio;
>>> +
>>> +    if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>>> +        return;
>>> +
>>> +    control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>>> +    control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
>>> +
>>> +    control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
>>> +             HIBMC_PW_MODE_CTL_MODE_MASK;
>>> +
>>> +
>>> +    /* Set up other fields in Power Control Register */
>>> +    if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
>>> +        control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>>> +        control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
>>> +                 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>>> +    } else {
>>> +        control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>>> +        control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
>>> +                 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>>> +
>>> +    }
>>> +    /* Program new power mode. */
>>> +    writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>>> +}
>>> +
>>> +static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
>>> +{
>>> +    void __iomem   *mmio = hidev->mmio;
>>> +
>>> +    return (readl(mmio + HIBMC_POWER_MODE_CTRL)&
>>> +        HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>>> +}
>>> +
>>> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
>>> +{
>>> +    unsigned int gate_reg;
>>> +    unsigned int mode;
>>> +    void __iomem   *mmio = hidev->mmio;
>>> +
>>> +    /* Get current power mode. */
>>> +    mode = hibmc_get_power_mode(hidev);
>>> +
>>> +    switch (mode) {
>>> +    case HIBMC_PW_MODE_CTL_MODE_MODE0:
>>> +        gate_reg = HIBMC_MODE0_GATE;
>>> +        break;
>>> +
>>> +    case HIBMC_PW_MODE_CTL_MODE_MODE1:
>>> +        gate_reg = HIBMC_MODE1_GATE;
>>> +        break;
>>> +
>>> +    default:
>>> +        gate_reg = HIBMC_MODE0_GATE;
>>> +        break;
>>> +    }
>>> +    writel(gate, mmio + gate_reg);
>>> +}
>>> +
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>>> new file mode 100644
>>> index 0000000..39f7a17
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>>> @@ -0,0 +1,28 @@
>>> +/* Hisilicon Hibmc SoC drm driver
>>> + *
>>> + * Based on the bochs drm driver.
>>> + *
>>> + * Copyright (c) 2016 Huawei Limited.
>>> + *
>>> + * Author:
>>> + *    Rongrong Zou <zourongrong@huawei>
>>> + *    Rongrong Zou <[email-masked]>
>>> + *    Jianhua Li <[email-masked]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifndef HIBMC_DRM_POWER_H
>>> +#define HIBMC_DRM_POWER_H
>>> +
>>> +#include "hibmc_drm_drv.h"
>>> +
>>> +extern void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>>> +                 unsigned int power_mode);
>>> +extern void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
>>> +                   unsigned int gate);
>>> +#endif
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>> new file mode 100644
>>> index 0000000..4966c42
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>> @@ -0,0 +1,214 @@
>>> +/* Hisilicon Hibmc SoC drm driver
>>> + *
>>> + * Based on the bochs drm driver.
>>> + *
>>> + * Copyright (c) 2016 Huawei Limited.
>>> + *
>>> + * Author:
>>> + *    Rongrong Zou <zourongrong@huawei>
>>> + *    Rongrong Zou <[email-masked]>
>>> + *    Jianhua Li <[email-masked]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + *
>>> + */
>>> +
>>> +#ifndef HIBMC_DRM_HW_H
>>> +#define HIBMC_DRM_HW_H
>>> +
>>> +#define OFF 0
>>> +#define ON  1
>>> +#define DISABLE               0
>>> +#define ENABLE                1
>>> +
>>> +
>>> +
>>> +/* register definition */
>>> +#define HIBMC_MISC_CTRL                0x4
>>> +
>>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)        ((x) << 6)
>>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK    0x40
>>> +
>>> +#define RESET                0
>>> +#define NORMAL               1
>>> +
>>> +#define HIBMC_CURRENT_GATE            0x000040
>>> +#define HIBMC_CURR_GATE_DISPLAY(x)        ((x) << 2)
>>> +#define HIBMC_CURR_GATE_DISPLAY_MASK        0x4
>>> +
>>> +#define HIBMC_CURR_GATE_LOCALMEM(x)        ((x) << 1)
>>> +#define HIBMC_CURR_GATE_LOCALMEM_MASK        0x2
>>> +
>>> +#define HIBMC_MODE0_GATE            0x000044
>>> +#define HIBMC_MODE1_GATE            0x000048
>>> +#define HIBMC_POWER_MODE_CTRL            0x00004C
>>> +
>>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)        ((x) << 3)
>>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK    0x8
>>> +
>>> +#define HIBMC_PW_MODE_CTL_MODE(x)        ((x) << 0)
>>> +#define HIBMC_PW_MODE_CTL_MODE_MASK        0x03
>>> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT        0
>>> +
>>> +
>>> +#define HIBMC_PW_MODE_CTL_MODE_MODE0        0
>>> +#define HIBMC_PW_MODE_CTL_MODE_MODE1        1
>>> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP        2
>>> +
>>> +#define HIBMC_PANEL_PLL_CTRL            0x00005C
>>> +#define HIBMC_CRT_PLL_CTRL            0x000060
>>> +
>>> +#define HIBMC_PLL_CTRL_BYPASS(x)        ((x) << 18)
>>> +#define HIBMC_PLL_CTRL_BYPASS_MASK        0x40000
>>> +
>>> +#define HIBMC_PLL_CTRL_POWER(x)            ((x) << 17)
>>> +#define HIBMC_PLL_CTRL_POWER_MASK        0x20000
>>> +
>>> +#define HIBMC_PLL_CTRL_INPUT(x)            ((x) << 16)
>>> +#define HIBMC_PLL_CTRL_INPUT_MASK        0x10000
>>> +
>>> +#define OSC                    0
>>> +#define TESTCLK                    1
>>> +
>>> +#define HIBMC_PLL_CTRL_POD(x)            ((x) << 14)
>>> +#define HIBMC_PLL_CTRL_POD_MASK            0xC000
>>> +
>>> +#define HIBMC_PLL_CTRL_OD(x)            ((x) << 12)
>>> +#define HIBMC_PLL_CTRL_OD_MASK            0x3000
>>> +
>>> +#define HIBMC_PLL_CTRL_N(x)            ((x) << 8)
>>> +#define HIBMC_PLL_CTRL_N_MASK            0xF00
>>> +
>>> +#define HIBMC_PLL_CTRL_M(x)            ((x) << 0)
>>> +#define HIBMC_PLL_CTRL_M_MASK            0xFF
>>> +
>>> +
>>> +#define HIBMC_CRT_DISP_CTL            0x80200
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)        ((x) << 25)
>>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK    0x2000000
>>> +
>>> +#define CRTSELECT_VGA                0
>>> +#define CRTSELECT_CRT                1
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)    ((x) << 14)
>>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
>>> +
>>> +#define PHASE_ACTIVE_HIGH      0
>>> +#define PHASE_ACTIVE_LOW       1
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)    ((x) << 13)
>>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)    ((x) << 12)
>>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_TIMING(x)        ((x) << 8)
>>> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK        0x100
>>> +
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_PLANE(x)        ((x) << 2)
>>> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK        4
>>> +
>>> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)        ((x) << 0)
>>> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK        0x03
>>> +
>>> +
>>> +
>>> +#define HIBMC_CRT_FB_ADDRESS            0x080204
>>> +
>>> +#define HIBMC_CRT_FB_WIDTH            0x080208
>>> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)        ((x) << 16)
>>> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK        0x3FFF0000
>>> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)        ((x) << 0)
>>> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK        0x3FFF
>>> +
>>> +
>>> +#define HIBMC_CRT_HORZ_TOTAL            0x08020C
>>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)        ((x) << 16)
>>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK        0xFFF0000
>>> +
>>> +
>>> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(x)    ((x) << 0)
>>> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK    0xFFF
>>> +
>>> +#define HIBMC_CRT_HORZ_SYNC            0x080210
>>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)        ((x) << 16)
>>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK        0xFF0000
>>> +
>>> +#define HIBMC_CRT_HORZ_SYNC_START(x)        ((x) << 0)
>>> +#define HIBMC_CRT_HORZ_SYNC_START_MASK        0xFFF
>>> +
>>> +#define HIBMC_CRT_VERT_TOTAL            0x080214
>>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)        ((x) << 16)
>>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK        0x7FFF0000
>>> +
>>> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_END(x)    ((x) << 0)
>>> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK    0x7FF
>>> +
>>> +#define HIBMC_CRT_VERT_SYNC            0x080218
>>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)        ((x) << 16)
>>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK        0x3F0000
>>> +
>>> +
>>> +#define HIBMC_CRT_VERT_SYNC_START(x)        ((x) << 0)
>>> +#define HIBMC_CRT_VERT_SYNC_START_MASK        0x7FF
>>> +
>>> +/* Auto Centering */
>>> +#define HIBMC_CRT_AUTO_CENTERING_TL        0x080280
>>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)    ((x) << 16)
>>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK    0x7FF0000
>>> +
>>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
>>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK    0x7FF
>>> +
>>> +#define HIBMC_CRT_AUTO_CENTERING_BR        0x080284
>>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)    ((x) << 16)
>>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK    0x7FF0000
>>> +
>>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)    ((x) << 0)
>>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK    0x7FF
>>> +
>>> +/* register to control panel output */
>>> +#define DISPLAY_CONTROL_HISILE            0x80288
>>> +
>>> +/* register and values for PLL control */
>>> +#define CRT_PLL1_HS                0x802a8
>>> +#define CRT_PLL1_HS_25MHZ            0x23d40f02
>>> +#define CRT_PLL1_HS_40MHZ            0x23940801
>>> +#define CRT_PLL1_HS_65MHZ            0x23940d01
>>> +#define CRT_PLL1_HS_78MHZ            0x23540F82
>>> +#define CRT_PLL1_HS_74MHZ            0x23941dc2
>>> +#define CRT_PLL1_HS_80MHZ            0x23941001
>>> +#define CRT_PLL1_HS_80MHZ_1152            0x23540fc2
>>> +#define CRT_PLL1_HS_108MHZ            0x23b41b01
>>> +#define CRT_PLL1_HS_162MHZ            0x23480681
>>> +#define CRT_PLL1_HS_148MHZ            0x23541dc2
>>> +#define CRT_PLL1_HS_193MHZ            0x234807c1
>>> +
>>> +#define CRT_PLL2_HS                0x802ac
>>> +#define CRT_PLL2_HS_25MHZ            0x206B851E
>>> +#define CRT_PLL2_HS_40MHZ            0x30000000
>>> +#define CRT_PLL2_HS_65MHZ            0x40000000
>>> +#define CRT_PLL2_HS_78MHZ            0x50E147AE
>>> +#define CRT_PLL2_HS_74MHZ            0x602B6AE7
>>> +#define CRT_PLL2_HS_80MHZ            0x70000000
>>> +#define CRT_PLL2_HS_108MHZ            0x80000000
>>> +#define CRT_PLL2_HS_162MHZ            0xA0000000
>>> +#define CRT_PLL2_HS_148MHZ            0xB0CCCCCD
>>> +#define CRT_PLL2_HS_193MHZ            0xC0872B02
>>> +
>>> +/* Global macros */
>>> +#define RGB(r, g, b) \
>>> +( \
>>> +    (unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
>>> +)
>>> +
>>> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
>>> +
>>> +#define MB(x) ((x) << 20)
>>> +
>>> +#endif
>>> --
>>> 1.9.1
>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
>
>

-- 
Regards,
Rongrong