385 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Hisilicon Hibmc SoC drm driver3 *4 * Based on the bochs drm driver.5 *6 * Copyright (c) 2016 Huawei Limited.7 *8 * Author:9 * Rongrong Zou <zourongrong@huawei.com>10 * Rongrong Zou <zourongrong@gmail.com>11 * Jianhua Li <lijianhua@huawei.com>12 */13 14#include <linux/module.h>15#include <linux/pci.h>16 17#include <drm/drm_aperture.h>18#include <drm/drm_atomic_helper.h>19#include <drm/drm_drv.h>20#include <drm/drm_fbdev_ttm.h>21#include <drm/drm_gem_framebuffer_helper.h>22#include <drm/drm_gem_vram_helper.h>23#include <drm/drm_managed.h>24#include <drm/drm_module.h>25#include <drm/drm_vblank.h>26 27#include "hibmc_drm_drv.h"28#include "hibmc_drm_regs.h"29 30DEFINE_DRM_GEM_FOPS(hibmc_fops);31 32static irqreturn_t hibmc_interrupt(int irq, void *arg)33{34 struct drm_device *dev = (struct drm_device *)arg;35 struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);36 u32 status;37 38 status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);39 40 if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {41 writel(HIBMC_RAW_INTERRUPT_VBLANK(1),42 priv->mmio + HIBMC_RAW_INTERRUPT);43 drm_handle_vblank(dev, 0);44 }45 46 return IRQ_HANDLED;47}48 49static int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,50 struct drm_mode_create_dumb *args)51{52 return drm_gem_vram_fill_create_dumb(file, dev, 0, 128, args);53}54 55static const struct drm_driver hibmc_driver = {56 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,57 .fops = &hibmc_fops,58 .name = "hibmc",59 .date = "20160828",60 .desc = "hibmc drm driver",61 .major = 1,62 .minor = 0,63 .debugfs_init = drm_vram_mm_debugfs_init,64 .dumb_create = hibmc_dumb_create,65 .dumb_map_offset = drm_gem_ttm_dumb_map_offset,66};67 68static int __maybe_unused hibmc_pm_suspend(struct device *dev)69{70 struct drm_device *drm_dev = dev_get_drvdata(dev);71 72 return drm_mode_config_helper_suspend(drm_dev);73}74 75static int __maybe_unused hibmc_pm_resume(struct device *dev)76{77 struct drm_device *drm_dev = dev_get_drvdata(dev);78 79 return drm_mode_config_helper_resume(drm_dev);80}81 82static const struct dev_pm_ops hibmc_pm_ops = {83 SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,84 hibmc_pm_resume)85};86 87static const struct drm_mode_config_funcs hibmc_mode_funcs = {88 .mode_valid = drm_vram_helper_mode_valid,89 .atomic_check = drm_atomic_helper_check,90 .atomic_commit = drm_atomic_helper_commit,91 .fb_create = drm_gem_fb_create,92};93 94static int hibmc_kms_init(struct hibmc_drm_private *priv)95{96 struct drm_device *dev = &priv->dev;97 int ret;98 99 ret = drmm_mode_config_init(dev);100 if (ret)101 return ret;102 103 dev->mode_config.min_width = 0;104 dev->mode_config.min_height = 0;105 dev->mode_config.max_width = 1920;106 dev->mode_config.max_height = 1200;107 108 dev->mode_config.preferred_depth = 24;109 dev->mode_config.prefer_shadow = 1;110 111 dev->mode_config.funcs = (void *)&hibmc_mode_funcs;112 113 ret = hibmc_de_init(priv);114 if (ret) {115 drm_err(dev, "failed to init de: %d\n", ret);116 return ret;117 }118 119 ret = hibmc_vdac_init(priv);120 if (ret) {121 drm_err(dev, "failed to init vdac: %d\n", ret);122 return ret;123 }124 125 return 0;126}127 128/*129 * It can operate in one of three modes: 0, 1 or Sleep.130 */131void hibmc_set_power_mode(struct hibmc_drm_private *priv, u32 power_mode)132{133 u32 control_value = 0;134 void __iomem *mmio = priv->mmio;135 u32 input = 1;136 137 if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)138 return;139 140 if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)141 input = 0;142 143 control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);144 control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |145 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);146 control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);147 control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);148 writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);149}150 151void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)152{153 u32 gate_reg;154 u32 mode;155 void __iomem *mmio = priv->mmio;156 157 /* Get current power mode. */158 mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &159 HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;160 161 switch (mode) {162 case HIBMC_PW_MODE_CTL_MODE_MODE0:163 gate_reg = HIBMC_MODE0_GATE;164 break;165 166 case HIBMC_PW_MODE_CTL_MODE_MODE1:167 gate_reg = HIBMC_MODE1_GATE;168 break;169 170 default:171 gate_reg = HIBMC_MODE0_GATE;172 break;173 }174 writel(gate, mmio + gate_reg);175}176 177static void hibmc_hw_config(struct hibmc_drm_private *priv)178{179 u32 reg;180 181 /* On hardware reset, power mode 0 is default. */182 hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);183 184 /* Enable display power gate & LOCALMEM power gate*/185 reg = readl(priv->mmio + HIBMC_CURRENT_GATE);186 reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;187 reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;188 reg |= HIBMC_CURR_GATE_DISPLAY(1);189 reg |= HIBMC_CURR_GATE_LOCALMEM(1);190 191 hibmc_set_current_gate(priv, reg);192 193 /*194 * Reset the memory controller. If the memory controller195 * is not reset in chip,the system might hang when sw accesses196 * the memory.The memory should be resetted after197 * changing the MXCLK.198 */199 reg = readl(priv->mmio + HIBMC_MISC_CTRL);200 reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;201 reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);202 writel(reg, priv->mmio + HIBMC_MISC_CTRL);203 204 reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;205 reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);206 207 writel(reg, priv->mmio + HIBMC_MISC_CTRL);208}209 210static int hibmc_hw_map(struct hibmc_drm_private *priv)211{212 struct drm_device *dev = &priv->dev;213 struct pci_dev *pdev = to_pci_dev(dev->dev);214 resource_size_t ioaddr, iosize;215 216 ioaddr = pci_resource_start(pdev, 1);217 iosize = pci_resource_len(pdev, 1);218 priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize);219 if (!priv->mmio) {220 drm_err(dev, "Cannot map mmio region\n");221 return -ENOMEM;222 }223 224 return 0;225}226 227static int hibmc_hw_init(struct hibmc_drm_private *priv)228{229 int ret;230 231 ret = hibmc_hw_map(priv);232 if (ret)233 return ret;234 235 hibmc_hw_config(priv);236 237 return 0;238}239 240static int hibmc_unload(struct drm_device *dev)241{242 struct pci_dev *pdev = to_pci_dev(dev->dev);243 244 drm_atomic_helper_shutdown(dev);245 246 free_irq(pdev->irq, dev);247 248 pci_disable_msi(to_pci_dev(dev->dev));249 250 return 0;251}252 253static int hibmc_load(struct drm_device *dev)254{255 struct pci_dev *pdev = to_pci_dev(dev->dev);256 struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);257 int ret;258 259 ret = hibmc_hw_init(priv);260 if (ret)261 goto err;262 263 ret = drmm_vram_helper_init(dev, pci_resource_start(pdev, 0),264 pci_resource_len(pdev, 0));265 if (ret) {266 drm_err(dev, "Error initializing VRAM MM; %d\n", ret);267 goto err;268 }269 270 ret = hibmc_kms_init(priv);271 if (ret)272 goto err;273 274 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);275 if (ret) {276 drm_err(dev, "failed to initialize vblank: %d\n", ret);277 goto err;278 }279 280 ret = pci_enable_msi(pdev);281 if (ret) {282 drm_warn(dev, "enabling MSI failed: %d\n", ret);283 } else {284 /* PCI devices require shared interrupts. */285 ret = request_irq(pdev->irq, hibmc_interrupt, IRQF_SHARED,286 dev->driver->name, dev);287 if (ret)288 drm_warn(dev, "install irq failed: %d\n", ret);289 }290 291 /* reset all the states of crtc/plane/encoder/connector */292 drm_mode_config_reset(dev);293 294 return 0;295 296err:297 hibmc_unload(dev);298 drm_err(dev, "failed to initialize drm driver: %d\n", ret);299 return ret;300}301 302static int hibmc_pci_probe(struct pci_dev *pdev,303 const struct pci_device_id *ent)304{305 struct hibmc_drm_private *priv;306 struct drm_device *dev;307 int ret;308 309 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &hibmc_driver);310 if (ret)311 return ret;312 313 priv = devm_drm_dev_alloc(&pdev->dev, &hibmc_driver,314 struct hibmc_drm_private, dev);315 if (IS_ERR(priv)) {316 DRM_ERROR("failed to allocate drm_device\n");317 return PTR_ERR(priv);318 }319 320 dev = &priv->dev;321 pci_set_drvdata(pdev, dev);322 323 ret = pcim_enable_device(pdev);324 if (ret) {325 drm_err(dev, "failed to enable pci device: %d\n", ret);326 goto err_return;327 }328 329 ret = hibmc_load(dev);330 if (ret) {331 drm_err(dev, "failed to load hibmc: %d\n", ret);332 goto err_return;333 }334 335 ret = drm_dev_register(dev, 0);336 if (ret) {337 drm_err(dev, "failed to register drv for userspace access: %d\n",338 ret);339 goto err_unload;340 }341 342 drm_fbdev_ttm_setup(dev, 32);343 344 return 0;345 346err_unload:347 hibmc_unload(dev);348err_return:349 return ret;350}351 352static void hibmc_pci_remove(struct pci_dev *pdev)353{354 struct drm_device *dev = pci_get_drvdata(pdev);355 356 drm_dev_unregister(dev);357 hibmc_unload(dev);358}359 360static void hibmc_pci_shutdown(struct pci_dev *pdev)361{362 drm_atomic_helper_shutdown(pci_get_drvdata(pdev));363}364 365static const struct pci_device_id hibmc_pci_table[] = {366 { PCI_VDEVICE(HUAWEI, 0x1711) },367 {0,}368};369 370static struct pci_driver hibmc_pci_driver = {371 .name = "hibmc-drm",372 .id_table = hibmc_pci_table,373 .probe = hibmc_pci_probe,374 .remove = hibmc_pci_remove,375 .shutdown = hibmc_pci_shutdown,376 .driver.pm = &hibmc_pm_ops,377};378 379drm_module_pci_driver(hibmc_pci_driver);380 381MODULE_DEVICE_TABLE(pci, hibmc_pci_table);382MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");383MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");384MODULE_LICENSE("GPL v2");385