--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil -*-
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <tdm.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "graphics.h"
+#include "tdm-if.h"
+
+static gr_surface tdm_init(gr_backend *);
+static gr_surface tdm_flip(gr_backend *);
+static bool tdm_exit(gr_backend *);
+
+struct _tdm_data {
+ GRSurface gr_framebuffer;
+};
+
+static struct _tdm_data tdm_data;
+
+static gr_backend tdm_backend = {
+ .init = tdm_init,
+ .flip = tdm_flip,
+ .exit = tdm_exit,
+ .data = (void*)&tdm_data,
+};
+
+gr_backend *open_tdm(void)
+{
+ return &tdm_backend;
+}
+
+gr_surface tdm_init(gr_backend *backend)
+{
+ struct _tdm_data *data = (struct _tdm_data*)backend->data;
+ gr_surface gr_draw = (gr_surface)&data->gr_framebuffer;
+
+ if (tdm_if_display_init() < 0)
+ return NULL;
+
+ tdm_if_lcd_off();
+
+ gr_draw->width = tdm_if_display_width();
+ gr_draw->height = tdm_if_display_height();
+ gr_draw->pixel_bytes = 4; /* XXX */
+ gr_draw->row_bytes = tdm_if_display_stride();
+ gr_draw->data = malloc(tdm_if_display_bufsize());
+ if (gr_draw->data == NULL)
+ return NULL;
+
+ tdm_if_lcd_on();
+ return gr_draw;
+}
+
+gr_surface tdm_flip(gr_backend *backend)
+{
+ struct _tdm_data *data = (struct _tdm_data*)backend->data;
+ gr_surface gr_draw = (gr_surface)&data->gr_framebuffer;
+
+ tdm_if_buffer_update(gr_draw->data);
+ tdm_if_display_update();
+
+ return gr_draw;
+}
+
+bool tdm_exit(gr_backend *backend)
+{
+ struct _tdm_data *data = (struct _tdm_data*)backend->data;
+ gr_surface gr_draw = (gr_surface)&data->gr_framebuffer;
+
+ tdm_if_display_deinit();
+
+ if (gr_draw->data != NULL)
+ free(gr_draw->data);
+
+ return true;
+}
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil -*-
+ *
+ * system-recovery
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Based on tdm-if.c from tota-ua.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "tdm-if.h"
+
+#define LOGD(format, ...) printf("[TDM-IF] " format "\n", ##__VA_ARGS__)
+
+#define C(b, m) (((b) >> (m)) & 0xFF)
+#define B(c, s) ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a, b, c, d) (B(d, 24) | B(c, 16) | B(b, 8) | B(a, 0))
+#define FOURCC_STR(id) C(id, 0), C(id, 8), C(id, 16), C(id, 24)
+#define FOURCC_ID(str) FOURCC(((char*)str)[0], ((char*)str)[1], ((char*)str)[2], ((char*)str)[3])
+
+static tdm_if_disp s_st_disp;
+
+static void tdm_if_display_commit_handler_cb(tdm_output *output, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ LOGD("commit_handle_cb!!");
+
+ return ;
+}
+
+int tdm_if_display_init(void)
+{
+ const tdm_output_mode *output_modes, *preferred_mode;
+ tdm_info_layer layer_info;
+ tdm_layer_capability layer_caps;
+ tdm_output_conn_status conn_status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+ tdm_output_type output_type = TDM_OUTPUT_TYPE_Unknown;
+ tdm_output *output = NULL;
+ int buf_cnt;
+ tdm_error err = TDM_ERROR_NONE;
+ tdm_if_disp *st_disp = &s_st_disp;
+ int i, j;
+ int layer_count = 0;
+ int output_count = 0;
+
+ LOGD("START");
+
+ st_disp->disp = tdm_display_init(&err);
+ if (!st_disp->disp) {
+ LOGD("failed to init tdm_display. error num = %d", err);
+ goto exit;
+ }
+
+ err = tdm_display_get_fd(st_disp->disp, &st_disp->tdm_fd);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get tdm fd. error num = %d", err);
+ goto exit;
+ }
+
+ st_disp->drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
+ if (st_disp->drm_fd == -1) {
+ LOGD("failed to get tdm fd. error num = %d", err);
+ goto exit;
+ }
+
+ err = tdm_display_get_output_count(st_disp->disp, &output_count);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get output count. error num = %d", err);
+ goto exit;
+ }
+
+ if (output_count < 1) {
+ LOGD("insufficient number of outputs");
+ goto exit;
+ }
+
+ for (i = 0; i < output_count; i++) {
+ output = tdm_display_get_output(st_disp->disp, i, &err);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get outout. error num = %d", err);
+ goto exit;
+ }
+
+ err = tdm_output_get_output_type(output, &output_type);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get output type. error num = %d", err);
+ goto exit;
+ }
+
+ err = tdm_output_get_conn_status(output, &conn_status);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get output connection status. error num = %d", err);
+ goto exit;
+ }
+
+ LOGD("output_type=%d conn_status=%d", output_type, conn_status);
+ if ((output_type == TDM_OUTPUT_TYPE_LVDS) ||
+ (output_type == TDM_OUTPUT_TYPE_DSI)) {
+ int cnt = 0;
+ err = tdm_output_get_available_modes(output, &output_modes, &cnt);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get output available modes. error num = %d", err);
+ goto exit;
+ }
+ LOGD("%d output modes available", cnt);
+
+ preferred_mode = output_modes;
+ for (j = 0; j < cnt; j++) {
+ if (output_modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) {
+ preferred_mode = &output_modes[i];
+ break;
+ }
+ }
+
+ /* GET MODE INFO */
+ st_disp->output = output;
+ st_disp->width = preferred_mode->hdisplay;
+ st_disp->height = preferred_mode->vdisplay;
+
+ err = tdm_output_set_mode(st_disp->output, preferred_mode);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("unable to set mode: \"%s\"", preferred_mode->name);
+ goto exit;
+ }
+
+ /* informational */
+ unsigned int width_mm = 0;
+ unsigned int height_mm = 0;
+ err = tdm_output_get_physical_size(output, &width_mm, &height_mm);
+ LOGD("TDM_OUTPUT_MODE:name[%s] mode:wh[%d %d] mm[%d %d]",
+ preferred_mode->name, st_disp->width, st_disp->height, width_mm, height_mm);
+
+ break;
+ }
+ }
+
+ /* SET LAYER */
+ err = tdm_output_get_layer_count(st_disp->output, &layer_count);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get number of layers");
+ goto exit;
+ }
+ if (layer_count < 1) {
+ LOGD("insufficient number of layers: %d", layer_count);
+ goto exit;
+ }
+
+ for (i = 0; i < layer_count; i++) {
+ st_disp->layer = tdm_output_get_layer(st_disp->output, i, &err);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get layer: %d", i);
+ goto exit;
+ }
+
+ err = tdm_layer_get_capabilities(st_disp->layer, &layer_caps);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get layer capabilities: %d", i);
+ goto exit;
+ }
+
+ if ((layer_caps & TDM_LAYER_CAPABILITY_PRIMARY) &&
+ (layer_caps & TDM_LAYER_CAPABILITY_GRAPHIC))
+ break;
+ }
+
+ layer_info.src_config.size.h = st_disp->width;
+ layer_info.src_config.size.v = st_disp->height;
+ layer_info.src_config.pos.x = 0;
+ layer_info.src_config.pos.y = 0;
+ layer_info.src_config.pos.w = st_disp->width;
+ layer_info.src_config.pos.h = st_disp->height;
+ layer_info.src_config.format = TBM_FORMAT_ARGB8888;
+ layer_info.dst_pos.x = 0;
+ layer_info.dst_pos.y = 0;
+ layer_info.dst_pos.w = st_disp->width;
+ layer_info.dst_pos.h = st_disp->height;
+ layer_info.transform = TDM_TRANSFORM_NORMAL;
+
+ err = tdm_layer_set_info(st_disp->layer, &layer_info);
+ if (err != TDM_ERROR_NONE) {
+ LOGD("failed to get output layer. error num = %d", err);
+ goto exit;
+ }
+
+ for (buf_cnt = 0; buf_cnt < MAX_BUF; buf_cnt++) {
+ tbm_surface_error_e e;
+ tbm_surface_info_s si;
+
+ st_disp->surf[buf_cnt] = tbm_surface_internal_create_with_flags(st_disp->width,
+ st_disp->height,
+ TBM_FORMAT_ARGB8888,
+ TBM_BO_SCANOUT);
+ e = get_last_result();
+ if (e != TBM_SURFACE_ERROR_NONE ||
+ !st_disp->surf[buf_cnt]){
+ LOGD("failed to create tbm_surface!");
+ goto exit;
+ }
+
+ e = tbm_surface_get_info(st_disp->surf[buf_cnt], &si);
+ if (e != TBM_SURFACE_ERROR_NONE) {
+ LOGD("failed to get info for tbm_surface!");
+ goto exit;
+ }
+
+ LOGD("surface created: %dx%d %c%c%c%c bpp:%d size:%d planes:%d stride:%d",
+ si.width, si.height,
+ FOURCC_STR(si.format),
+ si.bpp, si.size, si.num_planes,
+ si.planes[0].stride);
+
+ if (si.num_planes != 1) {
+ LOGD("unsupported number of planes: %d", si.num_planes);
+ goto exit;
+ }
+ st_disp->buffer_size = si.planes[0].size;
+ st_disp->stride = si.planes[0].stride;
+ }
+
+
+ st_disp->current_buf_id = 0;
+
+ for (i = 0; i < MAX_BUF; i++) {
+ tdm_if_buffer_update(NULL);
+ tdm_if_display_update();
+ }
+
+ LOGD("DONE");
+ return 0;
+exit:
+ tdm_if_display_deinit();
+ return -1;
+}
+
+void tdm_if_display_deinit(void)
+{
+ int buf_cnt = 0;
+ tdm_if_disp *st_disp = &s_st_disp;
+
+ tdm_if_lcd_off();
+
+ if (st_disp->disp != NULL) {
+ /* RELEASE RESOURCE */
+ for (buf_cnt = 0; buf_cnt < MAX_BUF; buf_cnt++) {
+ if (st_disp->surf[buf_cnt] != NULL)
+ tbm_surface_destroy(st_disp->surf[buf_cnt]);
+ }
+
+ tdm_display_deinit(st_disp->disp);
+ st_disp->disp = NULL;
+ }
+}
+
+int tdm_if_display_width(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+ return st_disp->width;
+}
+
+int tdm_if_display_height(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+ return st_disp->height;
+}
+
+int tdm_if_display_bufsize(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+ return st_disp->buffer_size;
+}
+
+int tdm_if_display_stride(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+ return st_disp->stride;
+}
+
+void tdm_if_buffer_update(unsigned char *buffer)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+ int buf_cnt = st_disp->current_buf_id;
+ tbm_surface_info_s tbm_surface_info;
+ tbm_surface_error_e err;
+ uint32_t *surface;
+
+ err = tbm_surface_map(st_disp->surf[buf_cnt], TBM_SURF_OPTION_WRITE, &tbm_surface_info);
+ if (err != TBM_SURFACE_ERROR_NONE) {
+ LOGD("tbm_surface_map failed!");
+ return;
+ }
+
+ surface = (uint32_t*)tbm_surface_info.planes[0].ptr;
+
+ if (buffer == NULL)
+ memset(surface, 0, st_disp->buffer_size);
+ else
+ memcpy(surface, buffer, st_disp->buffer_size);
+
+ tbm_surface_unmap(st_disp->surf[buf_cnt]);
+}
+
+void tdm_if_display_update(void)
+{
+ /* DISPLAY UPDATE */
+ int buf_cnt = 0;
+ tdm_if_disp *st_disp = &s_st_disp;
+
+ buf_cnt = st_disp->current_buf_id;
+ st_disp->current_buf_id = (st_disp->current_buf_id + 1)%MAX_BUF;
+
+ tdm_layer_set_buffer(st_disp->layer, st_disp->surf[buf_cnt]);
+
+ // TODO: sync or async??
+ tdm_output_commit(st_disp->output, 1, tdm_if_display_commit_handler_cb, st_disp);
+}
+
+void tdm_if_lcd_on(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+
+ LOGD("DPMS ON!");
+ tdm_output_set_dpms(st_disp->output, TDM_OUTPUT_DPMS_ON);
+}
+
+void tdm_if_lcd_off(void)
+{
+ tdm_if_disp *st_disp = &s_st_disp;
+
+ LOGD("DPMS OFF!");
+ tdm_output_set_dpms(st_disp->output, TDM_OUTPUT_DPMS_OFF);
+}