1/*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "drm_device.h"
17#include <string>
18#include <cerrno>
19#include <fcntl.h>
20#include <memory>
21#include <drm_fourcc.h>
22#include "display_log.h"
23#include "drm_display.h"
24
25namespace OHOS {
26namespace HDI {
27namespace DISPLAY {
28FdPtr DrmDevice::mDrmFd = nullptr;
29std::shared_ptr<DrmDevice> DrmDevice::mInstance;
30
31std::shared_ptr<HdiDeviceInterface> DrmDevice::Create()
32{
33    DISPLAY_LOGD();
34    if (mDrmFd == nullptr) {
35        const std::string name("rockchip");
36        int drmFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); // drmOpen(name.c_str(), nullptr);
37        if (drmFd < 0) {
38            DISPLAY_LOGE("drm file:%{public}s open failed %{public}s", name.c_str(), strerror(errno));
39            return nullptr;
40        }
41        DISPLAY_LOGD("the drm fd is %{public}d", drmFd);
42        mDrmFd = std::make_shared<HdiFd>(drmFd);
43    }
44    if (mInstance == nullptr) {
45        mInstance = std::make_shared<DrmDevice>();
46    }
47    return mInstance;
48}
49
50int DrmDevice::GetDrmFd()
51{
52    if (mDrmFd == nullptr) {
53        DISPLAY_LOGE("the drmfd is null not open");
54        return -1;
55    }
56    return mDrmFd->GetFd();
57}
58
59using PixelFormatConvertTbl = struct PixFmtConvertTbl {
60    uint32_t drmFormat;
61    PixelFormat pixFormat;
62};
63
64uint32_t DrmDevice::ConvertToDrmFormat(PixelFormat fmtIn)
65{
66    static const PixelFormatConvertTbl convertTable[] = {
67        {DRM_FORMAT_XBGR8888, PIXEL_FMT_RGBX_8888}, {DRM_FORMAT_ABGR8888, PIXEL_FMT_RGBA_8888},
68        {DRM_FORMAT_RGB888, PIXEL_FMT_RGB_888}, {DRM_FORMAT_RGB565, PIXEL_FMT_BGR_565},
69        {DRM_FORMAT_BGRX4444, PIXEL_FMT_BGRX_4444}, {DRM_FORMAT_BGRA4444, PIXEL_FMT_BGRA_4444},
70        {DRM_FORMAT_RGBA4444, PIXEL_FMT_RGBA_4444}, {DRM_FORMAT_RGBX4444, PIXEL_FMT_RGBX_4444},
71        {DRM_FORMAT_BGRX5551, PIXEL_FMT_BGRX_5551}, {DRM_FORMAT_BGRA5551, PIXEL_FMT_BGRA_5551},
72        {DRM_FORMAT_BGRX8888, PIXEL_FMT_BGRX_8888}, {DRM_FORMAT_ARGB8888, PIXEL_FMT_BGRA_8888},
73        {DRM_FORMAT_NV12, PIXEL_FMT_YCBCR_420_SP}, {DRM_FORMAT_NV21, PIXEL_FMT_YCRCB_420_SP},
74        {DRM_FORMAT_YUV420, PIXEL_FMT_YCBCR_420_P}, {DRM_FORMAT_YVU420, PIXEL_FMT_YCRCB_420_P},
75        {DRM_FORMAT_NV16, PIXEL_FMT_YCBCR_422_SP}, {DRM_FORMAT_NV61, PIXEL_FMT_YCRCB_422_SP},
76        {DRM_FORMAT_YUV422, PIXEL_FMT_YCBCR_422_P}, {DRM_FORMAT_YVU422, PIXEL_FMT_YCRCB_422_P},
77    };
78    uint32_t fmtOut = 0;
79    for (uint32_t i = 0; i < sizeof(convertTable) / sizeof(convertTable[0]); i++) {
80        if (convertTable[i].pixFormat == fmtIn) {
81            fmtOut = convertTable[i].drmFormat;
82        }
83    }
84    DISPLAY_LOGD("fmtIn %{public}d, outFmt %{public}d", fmtIn, fmtOut);
85    return fmtOut;
86}
87
88DrmDevice::DrmDevice() {}
89
90int32_t DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const std::string &name, DrmProperty &prop)
91{
92    return GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, name, prop);
93}
94
95int32_t DrmDevice::GetConnectorProperty(const DrmConnector &connector, const std::string &name, DrmProperty &prop)
96{
97    return GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR, name, prop);
98}
99
100int32_t DrmDevice::GetPlaneProperty(const DrmPlane &plane, const std::string &name, DrmProperty &prop)
101{
102    return GetProperty(plane.GetId(), DRM_MODE_OBJECT_PLANE, name, prop);
103}
104
105int32_t DrmDevice::GetProperty(uint32_t objId, uint32_t objType, const std::string &name, DrmProperty &prop)
106{
107    drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(GetDrmFd(), objId, objType);
108    DISPLAY_CHK_RETURN((!props), DISPLAY_FAILURE, DISPLAY_LOGE("can not get properties"));
109    bool found = false;
110    for (uint32_t i = 0; i < props->count_props; i++) {
111        drmModePropertyPtr p = drmModeGetProperty(GetDrmFd(), props->props[i]);
112        if (strcmp(p->name, name.c_str()) == 0) {
113            found = true;
114            prop.propId = p->prop_id;
115            prop.value = props->prop_values[i];
116            prop.name = p->name;
117            prop.flags = p->flags;
118
119            for (int i = 0; i < p->count_values; ++i) {
120                prop.values.push_back(p->values[i]);
121            }
122            for (int i = 0; i < p->count_enums; ++i) {
123                prop.enums.push_back(DrmPropertyEnum(&p->enums[i]));
124            }
125
126            for (int i = 0; i < p->count_blobs; ++i) {
127                prop.blob_ids.push_back(p->blob_ids[i]);
128            }
129            if (prop.flags & DRM_MODE_PROP_RANGE) {
130                prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_INT);
131            } else if (prop.flags & DRM_MODE_PROP_ENUM) {
132                prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_ENUM);
133            } else if (prop.flags & DRM_MODE_PROP_OBJECT) {
134                prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_OBJECT);
135            } else if (prop.flags & DRM_MODE_PROP_BLOB) {
136                prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BLOB);
137            } else if (prop.flags & DRM_MODE_PROP_BITMASK) {
138                prop.type = static_cast<uint32_t>(DrmPropertyType::DRM_PROPERTY_TYPE_BITMASK);
139            }
140        }
141        drmModeFreeProperty(p);
142    }
143    drmModeFreeObjectProperties(props);
144    return found ? DISPLAY_SUCCESS : DISPLAY_NOT_SUPPORT;
145}
146
147int32_t DrmDevice::Init()
148{
149    int ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
150    DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
151        DISPLAY_LOGE("DRM_CLIENT_CAP_UNIVERSAL_PLANES set failed %{public}s", strerror(errno)));
152    ret = drmSetClientCap(GetDrmFd(), DRM_CLIENT_CAP_ATOMIC, 1);
153    DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE,
154        DISPLAY_LOGE("DRM_CLIENT_CAP_ATOMIC set failed %{public}s", strerror(errno)));
155
156    ret = drmSetMaster(GetDrmFd());
157    DISPLAY_CHK_RETURN((ret), DISPLAY_FAILURE, DISPLAY_LOGE("can not set to master errno : %{public}d", errno));
158    DISPLAY_LOGE("chenyf master");
159    ret = drmIsMaster(GetDrmFd());
160    DISPLAY_CHK_RETURN((!ret), DISPLAY_FAILURE, DISPLAY_LOGE("is not master : %{public}d", errno));
161
162    return DISPLAY_SUCCESS;
163}
164
165void DrmDevice::DeInit()
166{
167    mDisplays.clear();
168    mCrtcs.clear();
169}
170
171void DrmDevice::FindAllCrtc(const drmModeResPtr &res)
172{
173    DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
174    mCrtcs.clear();
175    for (int i = 0; i < res->count_crtcs; i++) {
176        drmModeCrtcPtr crtc = drmModeGetCrtc(GetDrmFd(), res->crtcs[i]);
177        if (!crtc) {
178            DISPLAY_LOGE("can not get crtc %{public}d", i);
179            continue;
180        }
181        uint32_t crtc_id = crtc->crtc_id;
182        std::shared_ptr<DrmCrtc> drmCrtc = std::make_shared<DrmCrtc>(crtc, i);
183        int ret = drmCrtc->Init(*this);
184        drmModeFreeCrtc(crtc);
185        if (ret != DISPLAY_SUCCESS) {
186            DISPLAY_LOGE("crtc %{public}d init failed", i);
187            continue;
188        }
189        mCrtcs.emplace(crtc_id, std::move(drmCrtc));
190    }
191}
192
193void DrmDevice::FindAllEncoder(const drmModeResPtr &res)
194{
195    DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
196    mEncoders.clear();
197    for (int i = 0; i < res->count_encoders; i++) {
198        drmModeEncoderPtr encoder = drmModeGetEncoder(GetDrmFd(), res->encoders[i]);
199        if (!encoder) {
200            DISPLAY_LOGE("can not get encoder %{public}d", i);
201            continue;
202        }
203        std::shared_ptr<DrmEncoder> drmEncoder = std::make_shared<DrmEncoder>(*encoder);
204        mEncoders.emplace(encoder->encoder_id, std::move(drmEncoder));
205        drmModeFreeEncoder(encoder);
206    }
207    DISPLAY_LOGD("find encoder count %{public}zd", mEncoders.size());
208}
209
210void DrmDevice::FindAllConnector(const drmModeResPtr &res)
211{
212    DISPLAY_CHK_RETURN_NOT_VALUE((res == nullptr), DISPLAY_LOGE("the res is null"));
213    mConnectors.clear();
214    int ret;
215    for (int i = 0; i < res->count_connectors; i++) {
216        drmModeConnectorPtr connector = drmModeGetConnector(GetDrmFd(), res->connectors[i]);
217        if (!connector) {
218            DISPLAY_LOGE("can not get connector mode %{public}d", i);
219            continue;
220        }
221        std::shared_ptr<DrmConnector> drmConnector = std::make_shared<DrmConnector>(*connector, mDrmFd);
222        ret = drmConnector->Init(*this);
223        drmModeFreeConnector(connector);
224        if (ret != DISPLAY_SUCCESS) {
225            continue;
226        }
227        int connectorId = drmConnector->GetId();
228        mConnectors.emplace(connectorId, std::move(drmConnector));
229    }
230    DISPLAY_LOGD("find connector count %{public}zd", mConnectors.size());
231}
232
233void DrmDevice::FindAllPlane()
234{
235    mPlanes.clear();
236    int ret;
237    drmModePlaneResPtr planeRes = drmModeGetPlaneResources(GetDrmFd());
238    DISPLAY_CHK_RETURN_NOT_VALUE((planeRes == nullptr), DISPLAY_LOGE("can not get plane resource"));
239    DISPLAY_LOGD("count_planes %{public}d", planeRes->count_planes);
240    for (uint32_t i = 0; i < planeRes->count_planes; i++) {
241        drmModePlanePtr p = drmModeGetPlane(GetDrmFd(), planeRes->planes[i]);
242        if (!p) {
243            DISPLAY_LOGE("can not get plane %{public}d", i);
244            continue;
245        }
246        std::shared_ptr<DrmPlane> drmPlane = std::make_shared<DrmPlane>(*p);
247        DISPLAY_LOGD();
248        ret = drmPlane->Init(*this);
249        DISPLAY_LOGD();
250        drmModeFreePlane(p);
251        if (ret != DISPLAY_SUCCESS) {
252            DISPLAY_LOGE("drm plane %{public}d init failed", i);
253            continue;
254        }
255        mPlanes.emplace_back(std::move(drmPlane));
256    }
257    DISPLAY_LOGD("find plane count %{public}zd", mPlanes.size());
258}
259
260std::shared_ptr<DrmEncoder> DrmDevice::GetDrmEncoderFromId(uint32_t id)
261{
262    return nullptr;
263}
264
265std::shared_ptr<DrmConnector> DrmDevice::GetDrmConnectorFromId(uint32_t id)
266{
267    return nullptr;
268}
269
270std::shared_ptr<DrmCrtc> DrmDevice::GetDrmCrtcFromId(uint32_t id)
271{
272    return nullptr;
273}
274
275std::vector<std::shared_ptr<DrmPlane>> DrmDevice::GetDrmPlane(uint32_t pipe, uint32_t type)
276{
277    std::vector<std::shared_ptr<DrmPlane>> planes;
278    for (const auto &plane : mPlanes) {
279        if (plane->IsIdle() && ((1 << pipe) & plane->GetPossibleCrtcs()) && (type == plane->GetType())) {
280            planes.push_back(plane);
281        }
282    }
283    DISPLAY_LOGD("the planes count %{public}zd", planes.size());
284    return planes;
285}
286
287bool DrmDevice::HandleHotplug(uint32_t dispId, bool plugIn)
288{
289    uint32_t find = 0;
290    uint32_t connectorId;
291
292    for (auto &dispConnectorIdMap : dispConnectorIdMaps_) {
293        if (dispConnectorIdMap.first == dispId) {
294            connectorId = dispConnectorIdMap.second;
295            find = 1;
296            break;
297        }
298    }
299
300    if (find == 0) {
301        return false;
302    }
303
304    for (auto &connectorPair : mConnectors) {
305        auto connector = connectorPair.second;
306        if (connectorId == connector->GetId()) {
307            if (connector->HandleHotplug(mEncoders, mCrtcs, plugIn) == true) {
308                connector->Init(*this);
309                return true;
310            }
311        }
312    }
313    return false;
314}
315
316std::unordered_map<uint32_t, std::shared_ptr<HdiDisplay>> DrmDevice::DiscoveryDisplay()
317{
318    uint32_t dispId;
319    uint32_t connectorId;
320
321    dispConnectorIdMaps_.clear();
322    mDisplays.clear();
323    drmModeResPtr res = drmModeGetResources(GetDrmFd());
324    DISPLAY_CHK_RETURN((res == nullptr), mDisplays, DISPLAY_LOGE("can not get drm resource"));
325    // discovery all drm resource
326    FindAllCrtc(res);
327    FindAllEncoder(res);
328    FindAllConnector(res);
329    FindAllPlane();
330    DISPLAY_LOGD();
331    // travel all connector
332    for (auto &connectorPair : mConnectors) {
333        auto connector = connectorPair.second;
334        uint32_t crtcId = 0;
335        int32_t ret = connector->PickIdleCrtcId(mEncoders, mCrtcs, crtcId);
336        if (ret != DISPLAY_SUCCESS) {
337            continue;
338        }
339        DISPLAY_LOGD();
340
341        auto crtcIter = mCrtcs.find(crtcId);
342        if (crtcIter == mCrtcs.end()) {
343            DISPLAY_LOGE("can not find crtc for the id %{public}d", connector->GetId());
344            continue;
345        }
346        DISPLAY_LOGD();
347        auto crtc = crtcIter->second;
348        // create the display
349        std::shared_ptr<HdiDisplay> display = std::make_shared<DrmDisplay>(connector, crtc, mInstance);
350        DISPLAY_LOGD();
351        display->Init();
352        dispId = display->GetId();
353        connectorId = connector->GetId();
354        mDisplays.emplace(dispId, std::move(display));
355        dispConnectorIdMaps_.emplace(dispId, connectorId);
356    }
357    DISPLAY_LOGD("find display size %{public}zd", mDisplays.size());
358    return mDisplays;
359}
360} // namespace OHOS
361} // namespace HDI
362} // namespace DISPLAY
363