1 /* Hisilicon Hibmc SoC drm driver 2 * 3 * Based on the bochs drm driver. 4 * 5 * Copyright (c) 2016 Huawei Limited. 6 * 7 * Author: 8 * Rongrong Zou <zourongrong@huawei.com> 9 * Rongrong Zou <zourongrong@gmail.com> 10 * Jianhua Li <lijianhua@huawei.com> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 */ 18 19 #include <drm/drm_atomic_helper.h> 20 #include <drm/drm_crtc_helper.h> 21 22 #include "hibmc_drm_drv.h" 23 #include "hibmc_drm_regs.h" 24 25 static int hibmc_connector_get_modes(struct drm_connector *connector) 26 { 27 return drm_add_modes_noedid(connector, 800, 600); 28 } 29 30 static enum drm_mode_status hibmc_connector_mode_valid(struct drm_connector *connector, 31 struct drm_display_mode *mode) 32 { 33 return MODE_OK; 34 } 35 36 static struct drm_encoder * 37 hibmc_connector_best_encoder(struct drm_connector *connector) 38 { 39 return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]); 40 } 41 42 static const struct drm_connector_helper_funcs 43 hibmc_connector_helper_funcs = { 44 .get_modes = hibmc_connector_get_modes, 45 .mode_valid = hibmc_connector_mode_valid, 46 .best_encoder = hibmc_connector_best_encoder, 47 }; 48 49 static const struct drm_connector_funcs hibmc_connector_funcs = { 50 .fill_modes = drm_helper_probe_single_connector_modes, 51 .destroy = drm_connector_cleanup, 52 .reset = drm_atomic_helper_connector_reset, 53 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 54 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 55 }; 56 57 static struct drm_connector * 58 hibmc_connector_init(struct hibmc_drm_private *priv) 59 { 60 struct drm_device *dev = priv->dev; 61 struct drm_connector *connector; 62 int ret; 63 64 connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL); 65 if (!connector) { 66 DRM_ERROR("failed to alloc memory when init connector\n"); 67 return ERR_PTR(-ENOMEM); 68 } 69 70 ret = drm_connector_init(dev, connector, 71 &hibmc_connector_funcs, 72 DRM_MODE_CONNECTOR_VGA); 73 if (ret) { 74 DRM_ERROR("failed to init connector: %d\n", ret); 75 return ERR_PTR(ret); 76 } 77 drm_connector_helper_add(connector, 78 &hibmc_connector_helper_funcs); 79 80 return connector; 81 } 82 83 static void hibmc_encoder_mode_set(struct drm_encoder *encoder, 84 struct drm_display_mode *mode, 85 struct drm_display_mode *adj_mode) 86 { 87 u32 reg; 88 struct drm_device *dev = encoder->dev; 89 struct hibmc_drm_private *priv = dev->dev_private; 90 91 reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); 92 reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1); 93 reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1); 94 reg |= HIBMC_DISPLAY_CONTROL_FPEN(1); 95 reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1); 96 writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE); 97 } 98 99 static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = { 100 .mode_set = hibmc_encoder_mode_set, 101 }; 102 103 static const struct drm_encoder_funcs hibmc_encoder_funcs = { 104 .destroy = drm_encoder_cleanup, 105 }; 106 107 int hibmc_vdac_init(struct hibmc_drm_private *priv) 108 { 109 struct drm_device *dev = priv->dev; 110 struct drm_encoder *encoder; 111 struct drm_connector *connector; 112 int ret; 113 114 connector = hibmc_connector_init(priv); 115 if (IS_ERR(connector)) { 116 DRM_ERROR("failed to create connector: %ld\n", 117 PTR_ERR(connector)); 118 return PTR_ERR(connector); 119 } 120 121 encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL); 122 if (!encoder) { 123 DRM_ERROR("failed to alloc memory when init encoder\n"); 124 return -ENOMEM; 125 } 126 127 encoder->possible_crtcs = 0x1; 128 ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs, 129 DRM_MODE_ENCODER_DAC, NULL); 130 if (ret) { 131 DRM_ERROR("failed to init encoder: %d\n", ret); 132 return ret; 133 } 134 135 drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs); 136 drm_connector_attach_encoder(connector, encoder); 137 138 return 0; 139 } 140