1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "hdf_drm_panel.h"
10 #include <drm/drmP.h>
11 #include <drm/drm_atomic_helper.h>
12 #include <linux/backlight.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/of_gpio.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regulator/consumer.h>
18 #include <video/mipi_display.h>
19 #include <video/of_display_timing.h>
20 #include <video/videomode.h>
21 #include "osal_mem.h"
22
ToHdfDrmPanel(const struct drm_panel * panel)23 static inline struct HdfDrmPanel *ToHdfDrmPanel(const struct drm_panel *panel)
24 {
25 return container_of(panel, struct HdfDrmPanel, panel);
26 }
27
HdfDrmPanelUnprepare(struct drm_panel * panel)28 static int HdfDrmPanelUnprepare(struct drm_panel *panel)
29 {
30 return 0;
31 }
32
HdfDrmPanelPrepare(struct drm_panel * panel)33 static int HdfDrmPanelPrepare(struct drm_panel *panel)
34 {
35 return 0;
36 }
37
HdfDrmPanelDisable(struct drm_panel * panel)38 static int HdfDrmPanelDisable(struct drm_panel *panel)
39 {
40 struct HdfDrmPanel *hdfDrmPanel = ToHdfDrmPanel(panel);
41 struct PanelData *panelData;
42
43 HDF_LOGD("%s line = %d\n", __func__, __LINE__);
44 OsalMutexLock(&hdfDrmPanel->manager->dispMutex);
45 panelData = hdfDrmPanel->manager->panelManager->panel[hdfDrmPanel->index];
46 panelData->off(panelData);
47 OsalMutexUnlock(&hdfDrmPanel->manager->dispMutex);
48 return HDF_SUCCESS;
49 }
50
HdfDrmPanelEnable(struct drm_panel * panel)51 static int HdfDrmPanelEnable(struct drm_panel *panel)
52 {
53 struct HdfDrmPanel *hdfDrmPanel = ToHdfDrmPanel(panel);
54 struct PanelData *panelData;
55
56 HDF_LOGD("%s line = %d\n", __func__, __LINE__);
57 panelData = hdfDrmPanel->manager->panelManager->panel[hdfDrmPanel->index];
58 OsalMutexLock(&hdfDrmPanel->manager->dispMutex);
59 panelData->on(panelData);
60 OsalMutexUnlock(&hdfDrmPanel->manager->dispMutex);
61 return HDF_SUCCESS;
62 }
63
HdfDrmPanelGetModes(struct drm_panel * panel)64 static int HdfDrmPanelGetModes(struct drm_panel *panel)
65 {
66 struct drm_connector *connector = panel->connector;
67 struct HdfDrmPanel *hdfDrmPanel = ToHdfDrmPanel(panel);
68 struct drm_display_mode *mode = NULL;
69 struct PanelInfo *panelInfo = NULL;
70
71 HDF_LOGD("%s line = %d\n", __func__, __LINE__);
72 panelInfo = hdfDrmPanel->manager->panelManager->panel[hdfDrmPanel->index]->info;
73 mode = drm_mode_duplicate(panel->drm, &hdfDrmPanel->mode);
74 if (!mode) {
75 HDF_LOGE("failed to add mode %ux%ux@%u",
76 hdfDrmPanel->mode.hdisplay, hdfDrmPanel->mode.vdisplay,
77 hdfDrmPanel->mode.vrefresh);
78 return -ENOMEM;
79 }
80 drm_mode_set_name(mode);
81 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
82 drm_mode_probed_add(connector, mode);
83 connector->display_info.width_mm = panelInfo->pWidth;
84 connector->display_info.height_mm = panelInfo->pHeight;
85 return 1;
86 }
87
88 static struct drm_panel_funcs g_hdfDrmPanelFuncs = {
89 .get_modes = HdfDrmPanelGetModes,
90 .enable = HdfDrmPanelEnable,
91 .disable = HdfDrmPanelDisable,
92 .prepare = HdfDrmPanelPrepare,
93 .unprepare = HdfDrmPanelUnprepare,
94 };
95
SuspendStore(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)96 static ssize_t SuspendStore(struct device *dev,
97 struct device_attribute *attr, const char *buf, size_t count)
98 {
99 int32_t ret;
100 struct HdfDrmPanel *hdfDrmPanel = dev_get_drvdata(dev);
101
102 ret = HdfDrmPanelDisable(&hdfDrmPanel->panel);
103 if (ret != HDF_SUCCESS) {
104 HDF_LOGE("%s HdfDrmPanelDisable fail", __func__);
105 return count;
106 }
107 ret = HdfDrmPanelUnprepare(&hdfDrmPanel->panel);
108 if (ret != HDF_SUCCESS) {
109 HDF_LOGE("%s HdfDrmPanelUnprepare fail", __func__);
110 return count;
111 }
112 return count;
113 }
114 static DEVICE_ATTR(suspend, S_IWUSR, NULL, SuspendStore);
115
ResumeStore(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)116 static ssize_t ResumeStore(struct device *dev,
117 struct device_attribute *attr, const char *buf, size_t count)
118 {
119 int32_t ret;
120 struct HdfDrmPanel *hdfDrmPanel = dev_get_drvdata(dev);
121
122 ret = HdfDrmPanelPrepare(&hdfDrmPanel->panel);
123 if (ret != HDF_SUCCESS) {
124 HDF_LOGE("%s HdfDrmPanelPrepare fail", __func__);
125 return count;
126 }
127 ret = HdfDrmPanelEnable(&hdfDrmPanel->panel);
128 if (ret != HDF_SUCCESS) {
129 HDF_LOGE("%s HdfDrmPanelEnable fail", __func__);
130 return count;
131 }
132 return count;
133 }
134 static DEVICE_ATTR(resume, S_IWUSR, NULL, ResumeStore);
135
BacklightStore(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)136 static ssize_t BacklightStore(struct device *dev,
137 struct device_attribute *attr, const char *buf, size_t count)
138 {
139 int32_t ret;
140 unsigned long level;
141 struct PanelData *panel = NULL;
142 struct HdfDrmPanel *hdfDrmPanel = dev_get_drvdata(dev);
143
144 ret = kstrtoul(buf, 0, &level);
145 if (ret != 0) {
146 return ret;
147 }
148 HDF_LOGI("%s enter", __func__);
149 OsalMutexLock(&hdfDrmPanel->manager->dispMutex);
150 panel = hdfDrmPanel->manager->panelManager->panel[hdfDrmPanel->index];
151 OsalMutexUnlock(&hdfDrmPanel->manager->dispMutex);
152 ret = UpdateBrightness(panel->blDev, level);
153 if (ret != HDF_SUCCESS) {
154 HDF_LOGE("%s UpdateBrightness fail", __func__);
155 }
156
157 return count;
158 }
159 static DEVICE_ATTR(backlight, S_IWUSR, NULL, BacklightStore);
160
161 #define ATTR_NUM 3
162 static struct device_attribute *g_panelAttrs[] = {
163 &dev_attr_suspend,
164 &dev_attr_resume,
165 &dev_attr_backlight,
166 NULL,
167 };
168
CreateDrmMode(struct HdfDrmPanel * hdfDrmPanel)169 static void CreateDrmMode(struct HdfDrmPanel *hdfDrmPanel)
170 {
171 uint32_t panelIndex;
172 struct PanelInfo *panelInfo = NULL;
173
174 panelIndex = hdfDrmPanel->index;
175 panelInfo = hdfDrmPanel->manager->panelManager->panel[panelIndex]->info;
176 hdfDrmPanel->mode.clock = panelInfo->clockFreq / 1000;
177 hdfDrmPanel->mode.hdisplay = panelInfo->width;
178 hdfDrmPanel->mode.hsync_start = panelInfo->width + panelInfo->hfp;
179 hdfDrmPanel->mode.hsync_end = panelInfo->width + panelInfo->hfp + panelInfo->hsw;
180 hdfDrmPanel->mode.htotal = panelInfo->width + panelInfo->hfp + panelInfo->hsw + panelInfo->hbp;
181 hdfDrmPanel->mode.vdisplay = panelInfo->height;
182 hdfDrmPanel->mode.vsync_start = panelInfo->height + panelInfo->vfp;
183 hdfDrmPanel->mode.vsync_end = panelInfo->height + panelInfo->vfp + panelInfo->vsw;
184 hdfDrmPanel->mode.vtotal = panelInfo->height + panelInfo->vfp + panelInfo->vsw + panelInfo->vbp;
185 hdfDrmPanel->mode.flags = 0;
186 hdfDrmPanel->mode.vrefresh = drm_mode_vrefresh(&hdfDrmPanel->mode);
187 }
188
InstanceHdfDrmPanel(struct DispManager * manager,int32_t index)189 static struct HdfDrmPanel *InstanceHdfDrmPanel(struct DispManager *manager, int32_t index)
190 {
191 struct HdfDrmPanel *hdfDrmPanel = NULL;
192
193 hdfDrmPanel = (struct HdfDrmPanel *)OsalMemCalloc(sizeof(struct HdfDrmPanel));
194 if (hdfDrmPanel == NULL) {
195 HDF_LOGE("%s hdfDrmPanel malloc fail", __func__);
196 return NULL;
197 }
198 hdfDrmPanel->index = index;
199 hdfDrmPanel->manager = manager;
200 CreateDrmMode(hdfDrmPanel);
201 hdfDrmPanel->panel.funcs = &g_hdfDrmPanelFuncs;
202 return hdfDrmPanel;
203 }
204
HdfDrmPanelEntryInit(struct HdfDeviceObject * object)205 int32_t HdfDrmPanelEntryInit(struct HdfDeviceObject *object)
206 {
207 uint32_t ret;
208 uint32_t panelNum;
209 struct HdfDrmPanel *hdfDrmPanel = NULL;
210 struct mipi_dsi_device *dsiDev = NULL;
211 struct DispManager *manager = NULL;
212
213 manager = GetDispManager();
214 if (manager == NULL) {
215 HDF_LOGE("%s manager is null", __func__);
216 return HDF_FAILURE;
217 }
218 panelNum = manager->panelManager->panelNum;
219 for (uint32_t i = 0; i < panelNum; i++) {
220 hdfDrmPanel = InstanceHdfDrmPanel(manager, i);
221 if (hdfDrmPanel == NULL) {
222 return HDF_FAILURE;
223 }
224 dsiDev = (struct mipi_dsi_device *)manager->panelManager->panel[i]->priv;
225 hdfDrmPanel->panel.dev = &dsiDev->dev;
226 drm_panel_init(&hdfDrmPanel->panel);
227 ret = drm_panel_add(&hdfDrmPanel->panel);
228 if (ret) {
229 HDF_LOGE("%s drm_panel_add() failed", __func__);
230 return ret;
231 }
232 ret = mipi_dsi_attach(dsiDev);
233 if (ret) {
234 HDF_LOGE("%s mipi_dsi_attach failed", __func__);
235 drm_panel_remove(&hdfDrmPanel->panel);
236 return ret;
237 }
238 mipi_dsi_set_drvdata(dsiDev, hdfDrmPanel);
239 for (uint32_t j = 0; j < ATTR_NUM; j++) {
240 if (device_create_file(&dsiDev->dev, g_panelAttrs[j]) != 0) {
241 HDF_LOGE("%s line = %d device_create_file fail", __func__, __LINE__);
242 }
243 }
244 HDF_LOGI("%s panel[%d] registered success", i, __func__);
245 }
246 HDF_LOGI("%s success", __func__);
247 return HDF_SUCCESS;
248 }
249
250 struct HdfDriverEntry g_hdfDrmPanelEntry = {
251 .moduleVersion = 1,
252 .moduleName = "HDF_DRMPANEL",
253 .Init = HdfDrmPanelEntryInit,
254 };
255
256 HDF_INIT(g_hdfDrmPanelEntry);
257