1 /*************************************************************************/ /*!
3 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4 @License Dual MIT/GPLv2
6 The contents of this file are subject to the MIT license as set out below.
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
18 Alternatively, the contents of this file may be used under the terms of
19 the GNU General Public License Version 2 ("GPL") in which case the provisions
20 of GPL are applicable instead of those above.
22 If you wish to allow use of your version of this file only under the terms of
23 GPL, and not to allow others to use your version of this file under the terms
24 of the MIT license, indicate your decision by deleting the provisions above
25 and replace them with the notice and other provisions required by GPL as set
26 out in the file called "GPL-COPYING" included in this distribution. If you do
27 not delete the provisions above, a recipient may use your version of this file
28 under the terms of either the MIT license or GPL.
30 This License is also included in this distribution in the file called
33 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 */ /**************************************************************************/
44 #include <video/adf.h>
45 #include <video/adf_client.h>
46 #include <linux/slab.h>
47 #include <linux/seq_file.h>
48 #include <linux/debugfs.h>
50 #ifdef SUPPORT_ADF_SUNXI_FBDEV
51 #include <video/adf_fbdev.h>
54 #include PVR_ANDROID_ION_HEADER
55 #include PVR_ANDROID_SYNC_HEADER
57 #include <linux/sw_sync.h>
59 #include "adf_common.h"
60 #include "adf_sunxi.h"
62 #include "pvrmodule.h"
64 #define MAX_DISPLAYS 2
65 /* This is the maximum number of overlays per display
66 * Any global limitation validation must be done in either adf_sunxi_attach()
67 * or adf_sunxi_validate() */
68 #define NUM_OVERLAYS 4
69 #define NUM_BLENDER_PIPES 2
70 #define MAX_BUFFERS (MAX_DISPLAYS * NUM_OVERLAYS)
72 #define DEBUG_POST_DUMP_COUNT 4
73 #define VALIDATE_LOG_LINES 50
74 #define VALIDATE_LOG_LINE_SIZE 50
76 #ifdef ADF_VERBOSE_DEBUG
77 #define sunxi_dbg(x...) dev_dbg(x)
79 #define sunxi_dbg(...)
82 struct sunxi_interface {
83 struct adf_interface interface;
84 enum adf_interface_type adf_type;
87 int num_supported_modes;
88 struct drm_mode_modeinfo *supported_modes;
93 disp_output_type disp_type;
97 struct sunxi_overlay {
98 struct adf_overlay_engine overlay;
99 /* <0 means not attached, otherwise offset in sunxi.interfaces */
100 struct sunxi_interface *interface;
104 struct adf_device device;
106 struct sunxi_interface interfaces[MAX_DISPLAYS];
107 struct sunxi_overlay overlays[MAX_DISPLAYS][NUM_OVERLAYS];
108 struct ion_client *ion_client;
112 struct disp_composer_ops disp_ops;
114 /* Used to dump the last config to debugfs file */
115 struct setup_dispc_data last_config[DEBUG_POST_DUMP_COUNT];
116 u32 last_config_id[DEBUG_POST_DUMP_COUNT];
119 char validate_log[VALIDATE_LOG_LINES][VALIDATE_LOG_LINE_SIZE];
120 int validate_log_position;
122 struct dentry *debugfs_config_file;
123 struct dentry *debugfs_val_log;
126 atomic_t callbackcount;
128 wait_queue_head_t post_wait_queue;
130 #ifdef SUPPORT_ADF_SUNXI_FBDEV
131 struct adf_fbdev fbdev;
135 static const u32 sunxi_supported_formats[] = {
142 #define NUM_SUPPORTED_FORMATS ARRAY_SIZE(sunxi_supported_formats)
144 static void val_log(u32 post_id, const char *fmt, ...)
150 sunxi.validate_log_position = (sunxi.validate_log_position + 1)
151 % VALIDATE_LOG_LINES;
153 str = sunxi.validate_log[sunxi.validate_log_position];
155 offset = snprintf(str, VALIDATE_LOG_LINE_SIZE, "id %u:",
159 vsnprintf(str+offset, VALIDATE_LOG_LINE_SIZE-offset, fmt, args);
164 is_supported_format(u32 drm_format)
168 for (i = 0; i < NUM_SUPPORTED_FORMATS; i++) {
169 if (sunxi_supported_formats[i] == drm_format)
175 static disp_pixel_format
176 sunxi_format_to_disp(u32 format)
179 case DRM_FORMAT_BGRA8888:
180 return DISP_FORMAT_ARGB_8888;
181 case DRM_FORMAT_ARGB8888:
182 return DISP_FORMAT_BGRA_8888;
183 case DRM_FORMAT_BGRX8888:
184 return DISP_FORMAT_XRGB_8888;
185 case DRM_FORMAT_XRGB8888:
186 return DISP_FORMAT_BGRX_8888;
187 case DRM_FORMAT_YVU420:
188 return DISP_FORMAT_YUV420_P;
196 sunxi_format_has_alpha(u32 format)
199 case DRM_FORMAT_BGRA8888:
200 case DRM_FORMAT_ARGB8888:
202 case DRM_FORMAT_BGRX8888:
203 case DRM_FORMAT_XRGB8888:
204 case DRM_FORMAT_YVU420:
213 sunxi_format_bpp(u32 format)
216 case DRM_FORMAT_BGRA8888:
217 case DRM_FORMAT_BGRX8888:
218 case DRM_FORMAT_ARGB8888:
219 case DRM_FORMAT_XRGB8888:
221 case DRM_FORMAT_YVU420:
230 sunxi_format_uv_is_swapped(u32 format)
233 case DRM_FORMAT_BGRA8888:
234 case DRM_FORMAT_BGRX8888:
235 case DRM_FORMAT_ARGB8888:
236 case DRM_FORMAT_XRGB8888:
238 case DRM_FORMAT_YVU420:
247 buffer_is_scaled(const struct adf_buffer_config_ext *ext_config_data)
249 int srcWidth = ext_config_data->crop.x2 - ext_config_data->crop.x1;
250 int srcHeight = ext_config_data->crop.y2 - ext_config_data->crop.y1;
251 int dstWidth = ext_config_data->display.x2
252 - ext_config_data->display.x1;
253 int dstHeight = ext_config_data->display.y2
254 - ext_config_data->display.y1;
255 if (srcWidth != dstWidth ||
256 srcHeight != dstHeight)
263 sunxi_buffer_to_layer_info(const struct adf_buffer *buf,
264 const struct adf_buffer_config_ext *ext_config_data,
265 const struct adf_buffer_mapping *mappings, disp_layer_info *layer)
269 if (buffer_is_scaled(ext_config_data))
270 layer->mode = DISP_LAYER_WORK_MODE_SCALER;
272 layer->mode = DISP_LAYER_WORK_MODE_NORMAL;
274 /* Pipe/z are set in the parent function */
277 /* 0 = per-pixel alpha, 1 = global alpha */
278 switch (ext_config_data->blend_type) {
279 case ADF_BUFFER_BLENDING_NONE_EXT:
280 layer->alpha_mode = 1;
281 layer->alpha_value = 255;
283 case ADF_BUFFER_BLENDING_PREMULT_EXT:
284 if (sunxi_format_has_alpha(buf->format))
285 layer->alpha_mode = 0;
287 layer->alpha_mode = 1;
288 layer->alpha_value = ext_config_data->plane_alpha;
289 layer->fb.pre_multiply = true;
291 case ADF_BUFFER_BLENDING_COVERAGE_EXT:
292 dev_err(sunxi.dev, "Coverage blending not implemented\n");
295 dev_err(sunxi.dev, "Unknown blending type %d\n",
296 ext_config_data->blend_type);
300 layer->ck_enable = false;
301 layer->screen_win.x = ext_config_data->display.x1;
302 layer->screen_win.y = ext_config_data->display.y1;
303 layer->screen_win.width = ext_config_data->display.x2 -
304 ext_config_data->display.x1;
305 layer->screen_win.height = ext_config_data->display.y2 -
306 ext_config_data->display.y1;
309 for (plane = 0; plane < buf->n_planes; plane++) {
310 layer->fb.addr[plane] =
311 sg_phys(mappings->sg_tables[plane]->sgl) +
315 /* Fix up planar formats with VU plane ordering. For some
316 * reason this is not properly handled by the sunxi disp
319 if (sunxi_format_uv_is_swapped(buf->format)) {
320 unsigned int tmp = layer->fb.addr[1];
321 layer->fb.addr[1] = layer->fb.addr[2];
322 layer->fb.addr[2] = tmp;
326 layer->fb.size.width = buf->pitch[0] / sunxi_format_bpp(buf->format);
327 layer->fb.size.height = buf->h;
328 layer->fb.format = sunxi_format_to_disp(buf->format);
329 layer->fb.src_win.x = ext_config_data->crop.x1;
330 layer->fb.src_win.y = ext_config_data->crop.y1;
331 /* fb.src_win.width/height is only used for scaled layers */
332 layer->fb.src_win.width = ext_config_data->crop.x2 -
333 ext_config_data->crop.x1;
334 layer->fb.src_win.height = ext_config_data->crop.y2 -
335 ext_config_data->crop.y1;
341 adf_sunxi_open(struct adf_obj *obj, struct inode *inode, struct file *file)
343 atomic_inc(&sunxi.refcount);
347 static void adf_sunxi_set_hotplug_state(struct sunxi_interface *intf,
351 adf_sunxi_release(struct adf_obj *obj, struct inode *inode, struct file *file)
353 struct sync_fence *release_fence;
356 if (atomic_dec_return(&sunxi.refcount))
359 /* NULL flip to push buffer off screen */
360 release_fence = adf_device_post(obj->parent, NULL, 0, NULL, 0, NULL, 0);
362 if (IS_ERR_OR_NULL(release_fence)) {
363 dev_err(obj->parent->dev, "Failed to queue null flip command (err=%d)\n",
364 (int)PTR_ERR(release_fence));
368 /* Disable any hotplug events */
369 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
370 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_NONE)
372 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_HDMI)
373 adf_sunxi_set_hotplug_state(&sunxi.interfaces[dpy],
377 sync_fence_put(release_fence);
380 struct pipe_assignments {
381 int pipe[MAX_BUFFERS];
383 static void adf_sunxi_state_free(struct adf_device *dev, void *driver_state)
385 struct pipe_assignments *pipe_assignments =
388 kfree(pipe_assignments);
391 static int get_buf_display(struct adf_buffer *buf)
395 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
396 for (ovl = 0; ovl < NUM_OVERLAYS; ovl++) {
397 if (&sunxi.overlays[dpy][ovl].overlay ==
398 buf->overlay_engine) {
408 struct pipe_assignment_state {
409 int current_pipe[MAX_DISPLAYS];
410 int max_pipe[MAX_DISPLAYS];
411 int current_pipe_layers[MAX_DISPLAYS];
413 struct drm_clip_rect current_pipe_rects[MAX_DISPLAYS][NUM_OVERLAYS];
417 assign_pipe(struct pipe_assignment_state *state, int dpy, bool blended,
418 struct drm_clip_rect *display_rect)
420 struct drm_clip_rect *current_pipe_rects =
421 &state->current_pipe_rects[dpy][0];
424 /* The sunxi display block appears to support a single blender
425 * taking multiple input rects, so long as the blended
426 * rects do not overlap */
428 for (rect = 0; rect < state->current_pipe_layers[dpy]; rect++) {
429 const struct drm_clip_rect *layer_rect = &
430 current_pipe_rects[rect];
431 if (!adf_img_rects_intersect(layer_rect,
435 /* We need to assign a new pipe */
436 state->current_pipe[dpy]++;
437 state->current_pipe_layers[dpy] = 0;
438 if (state->current_pipe[dpy] >=
439 state->max_pipe[dpy]) {
444 current_pipe_rects[state->current_pipe_layers[dpy]] =
446 state->current_pipe_layers[dpy]++;
448 return state->current_pipe[dpy];
451 static int adf_sunxi_validate(struct adf_device *dev, struct adf_post *cfg,
455 struct adf_post_ext *post_ext = cfg->custom_data;
456 struct adf_buffer_config_ext *bufs_ext;
457 size_t expected_custom_data_size;
459 struct pipe_assignment_state pipe_state;
460 struct pipe_assignments *pipe_assignments;
461 bool scaler_in_use[MAX_DISPLAYS];
465 bool is_post = cfg->n_bufs && cfg->bufs[0].acquire_fence != NULL;
467 if (cfg->n_bufs == 0) {
468 val_log(0, "NULL flip\n");
473 dev_err(dev->dev, "Invalid custom data pointer\n");
476 post_id = post_ext->post_id;
478 expected_custom_data_size = sizeof(struct adf_post_ext)
479 + cfg->n_bufs * sizeof(struct adf_buffer_config_ext);
480 if (cfg->custom_data_size != expected_custom_data_size) {
481 dev_err(dev->dev, "Invalid custom data size - expected %u for %u buffers, got %u\n",
482 expected_custom_data_size, cfg->n_bufs,
483 cfg->custom_data_size);
487 bufs_ext = &post_ext->bufs_ext[0];
489 /* Reset blend pipe state */
490 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
491 scaler_in_use[dpy] = false;
492 pipe_state.current_pipe[dpy] = 0;
493 pipe_state.current_pipe_layers[dpy] = 0;
496 /* NOTE: The current method of assigning pipes over multiple displays
497 * is unknown and needs experimentation/documentation to correct.
498 * The current assumption is that there are 2 blend sources (pipe 0
499 * and 1) on the internal display, and only 1 (pipe 0) on hdmi */
500 if (sunxi.interfaces[DISPLAY_HDMI].connected) {
501 pipe_state.max_pipe[DISPLAY_HDMI] = 1;
502 pipe_state.current_pipe[DISPLAY_HDMI] = 0;
503 pipe_state.max_pipe[DISPLAY_INTERNAL] = NUM_BLENDER_PIPES;
504 pipe_state.current_pipe[DISPLAY_INTERNAL] = 1;
506 pipe_state.max_pipe[DISPLAY_INTERNAL] = NUM_BLENDER_PIPES;
507 pipe_state.current_pipe[DISPLAY_INTERNAL] = 0;
508 pipe_state.max_pipe[DISPLAY_HDMI] = 0;
509 pipe_state.current_pipe[DISPLAY_HDMI] = 0;
513 kzalloc(sizeof(struct pipe_assignments), GFP_KERNEL);
514 if (!pipe_assignments) {
515 dev_err(dev->dev, "Failed to allocate pipe assignment state\n");
517 goto err_free_assignments;
521 if (cfg->n_bufs > MAX_BUFFERS) {
522 dev_err(dev->dev, "Trying to post %d buffers (max %d)\n",
523 MAX_BUFFERS, NUM_OVERLAYS);
525 goto err_free_assignments;
528 for (i = 0; i < cfg->n_bufs; i++) {
530 struct adf_buffer *buf = &cfg->bufs[i];
531 struct adf_buffer_config_ext *ebuf = &bufs_ext[i];
533 dpy = get_buf_display(buf);
535 dev_err(dev->dev, "Buffer %d has invalid assigned overlay\n",
538 goto err_free_assignments;
542 adf_img_buffer_sanity_check(
543 &sunxi.interfaces[dpy].interface,
547 if (!buffer_is_sane) {
548 dev_err(dev->dev, "Buffer %d failed sanity check\n",
551 goto err_free_assignments;
554 if (!is_supported_format(buf->format)) {
555 /* This should be cleanly rejected when trying to assign
556 * an overlay engine */
557 dev_err(dev->dev, "Buffer %d has unrecognised format 0x%08x\n",
560 goto err_free_assignments;
562 if (buffer_is_scaled(ebuf)) {
563 /* The assumption is that there is a single scaled
564 * layer allowed per display, otherwise there may
565 * be a unbounded top end to the samples required per
566 * frame when testing validity a single layer at a time
568 if (scaler_in_use[dpy]) {
569 val_log(post_id, "Buffer %d is second scaled layer\n",
572 goto err_free_assignments;
574 scaler_in_use[dpy] = true;
575 if (!sunxi.disp_ops.is_support_scaler_layer(dpy,
576 ebuf->crop.x2 - ebuf->crop.x1,
577 ebuf->crop.y2 - ebuf->crop.y1,
578 ebuf->display.x2 - ebuf->display.x1,
579 ebuf->display.y2 - ebuf->display.y1)) {
580 val_log(post_id, "Buffer %d unsupported scaled layer\n",
583 goto err_free_assignments;
586 if (ebuf->transform != ADF_BUFFER_TRANSFORM_NONE_EXT) {
587 /* TODO: Sunxi transform support */
588 val_log(post_id, "Transformed layers not supported at the minute\n");
590 goto err_free_assignments;
593 if (ebuf->blend_type != ADF_BUFFER_BLENDING_NONE_EXT &&
594 ebuf->plane_alpha != 255 &&
595 sunxi_format_has_alpha(buf->format)) {
596 /* The sunxi display block appears to only support
597 * pixel /or/ global (plane) alpha, not both */
598 val_log(post_id, "Layer has both plane and pixel alpha\n");
600 goto err_free_assignments;
603 pipe = assign_pipe(&pipe_state, dpy,
604 ebuf->blend_type != ADF_BUFFER_BLENDING_NONE_EXT,
608 val_log(post_id, "Ran out of blend pipes\n");
610 goto err_free_assignments;
612 pipe_assignments->pipe[i] = pipe;
614 val_log(post_id, "Validate succeeded\n");
616 *driver_state = pipe_assignments;
619 err_free_assignments:
621 dev_err(dev->dev, "Failed validate for post\n");
622 kfree(pipe_assignments);
626 static void sunxi_retire_callback(void)
628 atomic_inc(&sunxi.callbackcount);
629 wake_up(&sunxi.post_wait_queue);
632 static bool sunxi_post_completed(u32 post_id)
634 return (atomic_read(&sunxi.callbackcount) >= post_id);
637 static void adf_sunxi_post(struct adf_device *adf_dev, struct adf_post *cfg,
640 struct setup_dispc_data *disp_data;
642 struct adf_post_ext *post_ext = cfg->custom_data;
643 struct adf_buffer_config_ext *ext_config_data = NULL;
644 int num_buffers[MAX_DISPLAYS];
646 struct pipe_assignments *pipe_assignments;
647 u32 post_count, post_id;
648 /* Allow a timeout of 4 frames before we force the frame off-screen */
650 msecs_to_jiffies((1000 / 60) * 4);
652 if (cfg->n_bufs == 0) {
653 val_log(0, "NULL flip\n");
657 BUG_ON(post_ext == NULL);
658 post_id = post_ext->post_id;
659 ext_config_data = &post_ext->bufs_ext[0];
660 val_log(post_id, "Posting\n");
663 pipe_assignments = driver_state;
664 if (!pipe_assignments && cfg->n_bufs != 0) {
665 dev_err(adf_dev->dev, "Invalid driver state\n");
669 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++)
670 num_buffers[dpy] = 0;
672 disp_data = kzalloc(sizeof(struct setup_dispc_data), GFP_KERNEL);
674 dev_err(adf_dev->dev, "Failed to allocate post data");
678 for (buf = 0; buf < cfg->n_bufs; buf++) {
680 dpy = get_buf_display(&cfg->bufs[buf]);
682 dev_err(adf_dev->dev, "Invalid overlay %p assigned to layer %d",
683 cfg->bufs[buf].overlay_engine, buf);
687 err = sunxi_buffer_to_layer_info(&cfg->bufs[buf],
688 &ext_config_data[buf],
690 &disp_data->layer_info[dpy][num_buffers[dpy]]);
693 dev_err(adf_dev->dev, "Failed to setup layer info (%d)\n",
697 disp_data->layer_info[dpy][num_buffers[dpy]].pipe =
698 pipe_assignments->pipe[buf];
699 disp_data->layer_info[dpy][num_buffers[dpy]].zorder = buf;
703 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
704 sunxi_dbg(adf_dev->dev, "Dpy %u has %u layers\n", dpy,
706 disp_data->layer_num[dpy] = num_buffers[dpy];
709 disp_data->hConfigData = disp_data;
711 sunxi.last_config_pos = (sunxi.last_config_pos + 1)
712 % DEBUG_POST_DUMP_COUNT;
714 sunxi.last_config[sunxi.last_config_pos] = *disp_data;
715 sunxi.last_config_id[sunxi.last_config_pos] = post_id;
717 err = sunxi.disp_ops.dispc_gralloc_queue(disp_data);
719 dev_err(adf_dev->dev, "Failed to queue post (%d)\n", err);
721 post_count = atomic_add_return(1, &sunxi.postcount);
723 if (wait_event_timeout(sunxi.post_wait_queue,
724 sunxi_post_completed(post_count-1), timeout) == 0) {
725 dev_err(sunxi.dev, "Timeout waiting for post callback\n");
735 static bool adf_sunxi_supports_event(struct adf_obj *obj,
736 enum adf_event_type type)
739 case ADF_OBJ_INTERFACE: {
740 struct adf_interface *intf =
741 container_of(obj, struct adf_interface, base);
742 struct sunxi_interface *sunxi_intf =
743 container_of(intf, struct sunxi_interface, interface);
745 case ADF_EVENT_VSYNC:
747 case ADF_EVENT_HOTPLUG:
748 /* Only support hotplug on HDMI displays */
749 return (sunxi_intf->disp_type == DISP_OUTPUT_TYPE_HDMI);
762 u32 width, height, refresh;
764 } hdmi_valid_modes[] = {
765 /* List of modes in preference order */
766 { 1920, 1080, 60, DISP_TV_MOD_1080P_60HZ},
767 { 1920, 1080, 50, DISP_TV_MOD_1080P_50HZ},
768 { 1280, 720, 60, DISP_TV_MOD_720P_60HZ},
769 { 1280, 720, 50, DISP_TV_MOD_720P_50HZ},
770 { 1920, 1080, 25, DISP_TV_MOD_1080P_25HZ},
771 { 1920, 1080, 30, DISP_TV_MOD_1080P_30HZ},
772 { 640, 480, 30, DISP_TV_MOD_480P},
774 #define NUM_HDMI_VALID_MODES \
775 (sizeof(hdmi_valid_modes)/sizeof(hdmi_valid_modes[0]))
777 static void setup_drm_mode(struct drm_mode_modeinfo *mode, int height,
778 int width, int refresh)
780 memset(mode, 0, sizeof(*mode));
782 mode->vrefresh = refresh;
783 mode->hdisplay = width;
784 mode->vdisplay = height;
786 adf_modeinfo_set_name(mode);
789 static void sunxi_disp_vsync_callback(void *user_data, u32 screen_id)
791 adf_vsync_notify(&sunxi.interfaces[screen_id].interface, ktime_get());
794 static int sunxi_disp_hotplug_callback(void *user_data,
795 disp_hotplug_state state)
797 struct sunxi_interface *intf = user_data;
802 dev_dbg(sunxi.dev, "%s: called state = %u\n", __func__, state);
804 /* Only HDMI displays can be hotplugged */
805 BUG_ON(intf->disp_type != DISP_OUTPUT_TYPE_HDMI);
807 kfree(intf->supported_modes);
808 intf->supported_modes = NULL;
809 intf->num_supported_modes = 0;
812 dev_err(sunxi.dev, "%s: Invalid hotplug state\n", __func__);
813 /* Fall-thru, treat as disconnect */
814 case DISP_HOTPLUG_DISCONNECT:
815 intf->connected = false;
816 adf_hotplug_notify_disconnected(&intf->interface);
817 dev_dbg(sunxi.dev, "%s: set disconnected\n", __func__);
819 case DISP_HOTPLUG_CONNECT:
820 intf->connected = true;
824 for (idx = 0; idx < NUM_HDMI_VALID_MODES; idx++) {
825 ret = sunxi.disp_ops.hdmi_check_support_mode(intf->display_id,
826 hdmi_valid_modes[idx].mode);
831 intf->num_supported_modes = mode_count;
832 if (mode_count == 0) {
833 dev_warn(sunxi.dev, "%s: No supported modes found for display id %d - forcing 720p\n",
834 __func__, intf->display_id);
835 intf->num_supported_modes = 1;
836 intf->supported_modes = kzalloc(
837 sizeof(struct drm_mode_modeinfo), GFP_KERNEL);
838 if (!intf->supported_modes) {
839 dev_err(sunxi.dev, "%s: Failed to allocate mode list\n",
843 /* Force the first mode in the supported list */
844 setup_drm_mode(&intf->supported_modes[0],
845 hdmi_valid_modes[0].height, hdmi_valid_modes[0].width,
846 hdmi_valid_modes[0].refresh);
848 unsigned int supported_idx = 0;
850 intf->num_supported_modes = mode_count;
851 intf->supported_modes = kzalloc(
852 mode_count * sizeof(struct drm_mode_modeinfo),
854 if (!intf->supported_modes) {
855 dev_err(sunxi.dev, "%s: Failed to allocate mode list\n",
859 for (idx = 0; idx < NUM_HDMI_VALID_MODES; idx++) {
860 if (sunxi.disp_ops.hdmi_check_support_mode(
862 hdmi_valid_modes[idx].mode) != 1) {
865 BUG_ON(supported_idx >= intf->num_supported_modes);
866 setup_drm_mode(&intf->supported_modes[supported_idx],
867 hdmi_valid_modes[idx].height,
868 hdmi_valid_modes[idx].width,
869 hdmi_valid_modes[idx].refresh);
872 BUG_ON(supported_idx != intf->num_supported_modes);
874 adf_hotplug_notify_connected(&intf->interface, intf->supported_modes,
875 intf->num_supported_modes);
876 /* Default to first mode */
877 ret = adf_interface_set_mode(&intf->interface,
878 &intf->supported_modes[0]);
880 dev_err(sunxi.dev, "%s: Failed hotplug modeset (%d)\n",
884 dev_dbg(sunxi.dev, "%s: set connect\n", __func__);
888 intf->num_supported_modes = 0;
889 kfree(intf->supported_modes);
890 intf->supported_modes = NULL;
894 static void adf_sunxi_set_hotplug_state(struct sunxi_interface *intf,
897 BUG_ON(intf->disp_type != DISP_OUTPUT_TYPE_HDMI);
898 dev_dbg(sunxi.dev, "%s: hotplug set to %s\n", __func__,
899 enabled ? "enabled" : "disabled");
901 sunxi.disp_ops.hotplug_enable(intf->display_id, true);
902 sunxi.disp_ops.hotplug_callback(intf->display_id, intf,
903 sunxi_disp_hotplug_callback);
904 sunxi.disp_ops.hdmi_enable(intf->display_id);
907 sunxi.disp_ops.hdmi_disable(intf->display_id);
908 sunxi.disp_ops.hotplug_enable(intf->display_id, false);
909 sunxi.disp_ops.hotplug_callback(intf->display_id, NULL, NULL);
914 static void adf_sunxi_set_event(struct adf_obj *obj, enum adf_event_type type,
918 case ADF_OBJ_INTERFACE: {
919 struct adf_interface *intf =
920 container_of(obj, struct adf_interface, base);
921 struct sunxi_interface *sunxi_intf =
922 container_of(intf, struct sunxi_interface, interface);
924 case ADF_EVENT_VSYNC:
925 sunxi.disp_ops.vsync_enable(sunxi_intf->display_id, enabled);
927 case ADF_EVENT_HOTPLUG:
928 adf_sunxi_set_hotplug_state(sunxi_intf, enabled);
942 find_matching_disp_tv_mode_id(struct drm_mode_modeinfo *mode)
946 for (idx = 0; idx < NUM_HDMI_VALID_MODES; idx++) {
947 if (hdmi_valid_modes[idx].width == mode->hdisplay &&
948 hdmi_valid_modes[idx].height == mode->vdisplay &&
949 hdmi_valid_modes[idx].refresh == mode->vrefresh) {
950 return hdmi_valid_modes[idx].mode;
953 dev_err(sunxi.dev, "%s: No matching disp_tv_mode for %ux%u@%u\n",
954 __func__, mode->hdisplay, mode->vdisplay, mode->vrefresh);
958 static int adf_sunxi_modeset(struct adf_interface *intf,
959 struct drm_mode_modeinfo *mode)
961 disp_tv_mode disp_mode;
963 struct sunxi_interface *sunxi_intf =
964 container_of(intf, struct sunxi_interface, interface);
966 dev_dbg(sunxi.dev, "%s: setting %d (type %d) to %ux%u@%u\n", __func__,
967 sunxi_intf->display_id, sunxi_intf->disp_type, mode->hdisplay,
968 mode->vdisplay, mode->vrefresh);
970 if (sunxi_intf->disp_type != DISP_OUTPUT_TYPE_HDMI) {
971 dev_dbg(sunxi.dev, "%s: Stub modeset for internal display\n",
976 disp_mode = find_matching_disp_tv_mode_id(mode);
978 dev_dbg(sunxi.dev, "%s: HDMI modeset to mode %d\n", __func__,
981 err = sunxi.disp_ops.hdmi_disable(sunxi_intf->display_id);
983 dev_err(sunxi.dev, "%s: Failed to disable display id %d for modeset\n",
984 __func__, sunxi_intf->display_id);
988 err = sunxi.disp_ops.hdmi_set_mode(sunxi_intf->display_id, disp_mode);
990 dev_err(sunxi.dev, "%s: Failed to set mode %ux%u@%u (id %d) to display id %d\n",
991 __func__, mode->hdisplay, mode->vdisplay,
992 mode->vrefresh, disp_mode, sunxi_intf->display_id);
996 err = sunxi.disp_ops.hdmi_enable(sunxi_intf->display_id);
998 dev_err(sunxi.dev, "%s: Failed to enable display id %d after modeset\n",
999 __func__, sunxi_intf->display_id);
1005 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1007 static int adf_sunxi_alloc_simple_buffer(struct adf_interface *intf, u16 w,
1008 u16 h, u32 format, struct dma_buf **dma_buf, u32 *offset, u32 *pitch)
1011 u32 bpp = sunxi_format_bpp(format);
1012 u32 size = h * w * bpp;
1013 struct ion_handle *hdl;
1014 struct adf_device *dev = intf->base.parent;
1017 dev_err(dev->dev, "%s: unknown format (0x%08x)\n",
1023 hdl = ion_alloc(sunxi.ion_client, size, 0,
1024 (1 << sunxi.ion_heap_id), 0);
1027 dev_err(dev->dev, "%s: ion_alloc failed (%d)\n",
1031 *dma_buf = ion_share_dma_buf(sunxi.ion_client, hdl);
1032 if (IS_ERR(*dma_buf)) {
1034 dev_err(dev->dev, "%s: ion_share_dma_buf failed (%d)\n",
1036 goto err_free_buffer;
1042 ion_free(sunxi.ion_client, hdl);
1047 static int adf_sunxi_describe_simple_post(struct adf_interface *intf,
1048 struct adf_buffer *fb, void *data, size_t *size)
1054 #endif /* SUPPORT_ADF_SUNXI_FBDEV */
1056 static struct adf_device_ops adf_sunxi_device_ops = {
1057 .owner = THIS_MODULE,
1059 .open = adf_sunxi_open,
1060 .release = adf_sunxi_release,
1061 .ioctl = adf_img_ioctl,
1063 .state_free = adf_sunxi_state_free,
1064 .validate = adf_sunxi_validate,
1065 .post = adf_sunxi_post,
1068 static struct adf_interface_ops adf_sunxi_interface_ops = {
1070 .supports_event = adf_sunxi_supports_event,
1071 .set_event = adf_sunxi_set_event,
1073 .modeset = adf_sunxi_modeset,
1074 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1075 .alloc_simple_buffer = adf_sunxi_alloc_simple_buffer,
1076 .describe_simple_post = adf_sunxi_describe_simple_post,
1080 static struct adf_overlay_engine_ops adf_sunxi_overlay_ops = {
1081 .supported_formats = &sunxi_supported_formats[0],
1082 .n_supported_formats = NUM_SUPPORTED_FORMATS,
1085 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1087 static struct fb_ops adf_sunxi_fb_ops = {
1088 .owner = THIS_MODULE,
1089 .fb_open = adf_fbdev_open,
1090 .fb_release = adf_fbdev_release,
1091 .fb_check_var = adf_fbdev_check_var,
1092 .fb_set_par = adf_fbdev_set_par,
1093 .fb_blank = adf_fbdev_blank,
1094 .fb_pan_display = adf_fbdev_pan_display,
1095 .fb_fillrect = cfb_fillrect,
1096 .fb_copyarea = cfb_copyarea,
1097 .fb_imageblit = cfb_imageblit,
1098 .fb_mmap = adf_fbdev_mmap,
1104 static void sunxi_debugfs_print_window(struct seq_file *s, const char *prefix,
1105 const disp_window *win)
1108 seq_printf(s, "%sx\t=\t%u\n", prefix, win->x);
1110 seq_printf(s, "%sy\t=\t%u\n", prefix, win->y);
1111 seq_printf(s, "%sw\t=\t%u\n", prefix, win->width);
1112 seq_printf(s, "%sh\t=\t%u\n", prefix, win->height);
1116 static void sunxi_debugfs_print_fb_info(struct seq_file *s, const char *prefix,
1117 const disp_fb_info *fb)
1121 for (i = 0; i < 3; i++)
1123 seq_printf(s, "%saddr[%d]\t=\t0x%08x\n", prefix, i,
1125 seq_printf(s, "%ssize.w\t=\t%u\n", prefix, fb->size.width);
1126 seq_printf(s, "%ssize.h\t=\t%u\n", prefix, fb->size.height);
1127 seq_printf(s, "%sformat\t=\t0x%x\n", prefix, fb->format);
1129 seq_printf(s, "%scs_mode\t=\t0x%x\n", prefix, fb->cs_mode);
1131 seq_printf(s, "%sb_trd_src\t=\t0x%x\n", prefix, fb->b_trd_src);
1133 seq_printf(s, "%strd_mode\t=\t0x%x\n", prefix, fb->trd_mode);
1134 for (i = 0; i < 3; i++)
1135 if (fb->trd_right_addr[i])
1136 seq_printf(s, "%strd_right_addr[%d]\t=\t0x%x\n", prefix,
1137 i, fb->trd_right_addr[i]);
1138 /* Default alpha mode is pre-multiply, so interesting values would
1140 if (fb->pre_multiply != 0x1)
1141 seq_printf(s, "%spre_multiply\t=\t0x%x\n", prefix,
1146 static void sunxi_debugfs_print_layer_info(struct seq_file *s, int layer_num,
1147 disp_layer_info *layer_info)
1151 for (i = 0; i < layer_num; i++) {
1152 disp_layer_info *layer = &layer_info[i];
1154 seq_printf(s, "\tlayer[%d] = {\n", i);
1156 seq_printf(s, "\t\tmode\t=\t0x%x\n", layer->mode);
1157 seq_printf(s, "\t\tpipe\t=\t0x%x\n", layer->pipe);
1158 seq_printf(s, "\t\tzorder\t=\t0x%x\n", layer->zorder);
1159 if (layer->alpha_mode)
1160 seq_printf(s, "\t\talpha_mode\t=\t0x%x\n",
1162 /* The default alpha is 0xff, so interesting values would be
1163 * when it does not equal 0xff */
1164 if (layer->alpha_value != 0xff)
1165 seq_printf(s, "\t\talpha_value\t=\t0x%x\n",
1166 layer->alpha_value);
1167 if (layer->ck_enable)
1168 seq_printf(s, "\t\tck_enable\t=\t0x%x\n",
1170 sunxi_debugfs_print_window(s, "\t\tscreen_win.",
1171 &layer->screen_win);
1172 sunxi_debugfs_print_fb_info(s, "\t\tfb.", &layer->fb);
1173 if (layer->b_trd_out)
1174 seq_printf(s, "\t\tb_trd_out\t=\t0x%x\n",
1176 if (layer->out_trd_mode)
1177 seq_printf(s, "\t\tout_trd_mode\t=\t0x%x\n",
1178 layer->out_trd_mode);
1179 seq_printf(s, "\t\tid\t=\t%u }\n", layer->id);
1183 static void sunxi_debugfs_print_config(struct seq_file *s, u32 post_id,
1184 struct setup_dispc_data *config)
1188 seq_printf(s, "adf_sunxi post_id %u = {\n", post_id);
1189 for (dpy = 0; dpy < 3; dpy++) {
1190 seq_printf(s, "\tlayer_num[%d] = %u\n", dpy,
1191 config->layer_num[dpy]);
1192 sunxi_debugfs_print_layer_info(s,
1193 config->layer_num[dpy],
1194 &config->layer_info[dpy][0]);
1199 static int sunxi_debugfs_show(struct seq_file *s, void *unused)
1201 /* FIXME: Should properly lock to reduce the risk of modification
1202 * while printing? */
1205 for (post = 0; post < DEBUG_POST_DUMP_COUNT; post++) {
1206 /* Start at current buffer position +1 (oldest post in the
1208 int pos = (sunxi.last_config_pos + post + 1)
1209 % DEBUG_POST_DUMP_COUNT;
1210 sunxi_debugfs_print_config(s, sunxi.last_config_id[pos],
1211 &sunxi.last_config[pos]);
1216 static int sunxi_debugfs_open(struct inode *inode, struct file *file)
1218 return single_open(file, sunxi_debugfs_show, inode->i_private);
1221 static const struct file_operations adf_sunxi_debugfs_fops = {
1222 .open = sunxi_debugfs_open,
1224 .llseek = seq_lseek,
1225 .release = single_release,
1228 static int sunxi_debugfs_val_show(struct seq_file *s, void *unused)
1232 for (line = 0; line < VALIDATE_LOG_LINES; line++) {
1233 int pos = (sunxi.validate_log_position + line + 1)
1234 % VALIDATE_LOG_LINES;
1235 seq_puts(s, sunxi.validate_log[pos]);
1240 static int sunxi_debugfs_val_open(struct inode *inode, struct file *file)
1242 return single_open(file, sunxi_debugfs_val_show, inode->i_private);
1245 static const struct file_operations adf_sunxi_debugfs_val_fops = {
1246 .open = sunxi_debugfs_val_open,
1248 .llseek = seq_lseek,
1249 .release = single_release,
1252 static int adf_init_lcd_interface(struct sunxi_interface *interface)
1258 interface->connected = true;
1259 interface->name = "LCD";
1260 interface->adf_type = ADF_INTF_DSI;
1261 err = adf_interface_init(&interface->interface, &sunxi.device,
1262 interface->adf_type, interface->display_id,
1263 ADF_INTF_FLAG_PRIMARY, &adf_sunxi_interface_ops,
1266 dev_err(sunxi.dev, "%s: Failed to init adf interface %d (%d)\n",
1267 __func__, interface->display_id, err);
1270 height = sunxi.disp_ops.get_screen_height(interface->display_id);
1272 dev_err(sunxi.dev, "%s: Failed to query display height (%d)\n",
1277 width = sunxi.disp_ops.get_screen_width(interface->display_id);
1279 dev_err(sunxi.dev, "%s: Failed to query display width (%d)\n",
1285 interface->supported_modes = kzalloc(sizeof(struct drm_mode_modeinfo),
1287 if (!interface->supported_modes) {
1288 dev_err(sunxi.dev, "%s: Failed to allocate mode struct\n",
1293 interface->num_supported_modes = 1;
1294 setup_drm_mode(&interface->supported_modes[0], height, width, refresh);
1296 err = adf_hotplug_notify_connected(&interface->interface,
1297 interface->supported_modes, interface->num_supported_modes);
1299 dev_err(sunxi.dev, "%s: Failed to notify connected (%d)\n",
1303 /* We need to set initial mode */
1304 err = adf_interface_set_mode(&interface->interface,
1305 &interface->supported_modes[0]);
1307 dev_err(sunxi.dev, "%s: Failed initial modeset (%d)\n",
1311 err = sunxi.disp_ops.vsync_callback(NULL, sunxi_disp_vsync_callback);
1313 dev_err(sunxi.dev, "%s: Failed to set vsync callback (%d)\n",
1322 static int adf_init_hdmi_interface(struct sunxi_interface *interface)
1324 disp_hotplug_state hotplug_state;
1327 interface->name = "HDMI";
1328 interface->adf_type = ADF_INTF_HDMI;
1329 hotplug_state = sunxi.disp_ops.hotplug_state(interface->display_id);
1331 err = adf_interface_init(&interface->interface, &sunxi.device,
1332 interface->adf_type, interface->display_id,
1333 ADF_INTF_FLAG_EXTERNAL, &adf_sunxi_interface_ops,
1336 dev_err(sunxi.dev, "%s: Failed to init adf interface %d (%d)\n",
1337 __func__, interface->display_id, err);
1341 switch (hotplug_state) {
1342 case DISP_HOTPLUG_CONNECT:
1343 interface->connected = true;
1346 dev_err(sunxi.dev, "%s: Error querying hotplug state for display id %d\n",
1347 __func__, interface->display_id);
1348 hotplug_state = DISP_HOTPLUG_DISCONNECT;
1349 /* Fall-thru, act as if disconnected*/
1350 case DISP_HOTPLUG_DISCONNECT:
1351 interface->connected = false;
1354 /* Call the hotplug function to setup modes */
1355 sunxi_disp_hotplug_callback(interface, hotplug_state);
1363 static void adf_init_interface(struct sunxi_interface *interface, int id)
1366 memset(interface, 0, sizeof(*interface));
1367 interface->disp_type = sunxi.disp_ops.get_output_type(id);
1368 interface->display_id = id;
1369 dev_dbg(sunxi.dev, "%s: interface %d\n", __func__, id);
1371 switch (interface->disp_type) {
1373 dev_err(sunxi.dev, "%s: Unsupported interface type %d for display %d\n",
1374 __func__, interface->disp_type, id);
1375 interface->disp_type = DISP_OUTPUT_TYPE_NONE;
1377 case DISP_OUTPUT_TYPE_NONE:
1378 dev_dbg(sunxi.dev, "%s: Skipping interface %d - type %d\n",
1379 __func__, id, interface->disp_type);
1380 interface->connected = false;
1382 case DISP_OUTPUT_TYPE_LCD:
1383 adf_init_lcd_interface(interface);
1385 case DISP_OUTPUT_TYPE_HDMI:
1386 adf_init_hdmi_interface(interface);
1391 static int adf_sunxi_probe(struct platform_device *pdev)
1397 memset(&sunxi.last_config, 0, sizeof(sunxi.last_config));
1399 atomic_set(&sunxi.postcount, 0);
1400 atomic_set(&sunxi.callbackcount, 0);
1401 init_waitqueue_head(&sunxi.post_wait_queue);
1403 sunxi.dev = &pdev->dev;
1405 err = adf_device_init(&sunxi.device, sunxi.dev,
1406 &adf_sunxi_device_ops, "sunxi_device");
1408 dev_err(sunxi.dev, "Failed to init ADF device (%d)\n",
1413 err = disp_get_composer_ops(&sunxi.disp_ops);
1415 dev_err(sunxi.dev, "Failed to get composer ops (%d)\n",
1417 goto err_free_overlays;
1419 /* Set the retire callback */
1420 err = sunxi.disp_ops.set_retire_callback(sunxi_retire_callback);
1422 dev_err(sunxi.dev, "Failed to set retire callback (%d)\n",
1424 goto err_free_overlays;
1426 /* The HDMI must be enabled to receive hotplug events, which in turn
1427 * must already must have a valid mode set */
1428 err = sunxi.disp_ops.hdmi_set_mode(1, DISP_TV_MOD_720P_60HZ);
1430 dev_warn(sunxi.dev, "Failed to enable initial hdmi mode on dpy 1 (%d)\n",
1434 dev_dbg(sunxi.dev, "%s: %d hdmi_enable\n", __func__, __LINE__);
1435 err = sunxi.disp_ops.hdmi_enable(1);
1437 dev_warn(sunxi.dev, "Failed to enable hdmi on dpy 1 (%d)\n",
1442 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++)
1443 adf_init_interface(&sunxi.interfaces[dpy], dpy);
1445 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
1446 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_NONE)
1448 for (ovl = 0; ovl < NUM_OVERLAYS; ovl++) {
1449 err = adf_overlay_engine_init(
1450 &sunxi.overlays[dpy][ovl].overlay,
1451 &sunxi.device, &adf_sunxi_overlay_ops,
1452 "sunxi_overlay_%d-%d", dpy, ovl);
1454 dev_err(sunxi.dev, "Failed to init overlay %d-%d (%d)\n",
1456 goto err_free_overlays;
1458 err = adf_attachment_allow(&sunxi.device,
1459 &sunxi.overlays[dpy][ovl].overlay,
1460 &sunxi.interfaces[dpy].interface);
1463 dev_err(sunxi.dev, "Failed to attach overlay %d-%d (%d)\n",
1465 goto err_free_overlays;
1471 sunxi.ion_heap_id = ION_HEAP_TYPE_CARVEOUT;
1473 sunxi.ion_client = ion_client_create(idev, "adf_sunxi");
1475 if (IS_ERR(sunxi.ion_client)) {
1476 err = PTR_ERR(sunxi.ion_client);
1477 dev_err(sunxi.dev, "Failed to create ion client (%d)\n",
1479 goto err_free_overlays;
1482 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1483 err = adf_fbdev_init(&sunxi.fbdev,
1484 &sunxi.interfaces[DISPLAY_INTERNAL].interface,
1485 &sunxi.overlays[DISPLAY_INTERNAL].overlay,
1486 sunxi.interfaces[DISPLAY_INTERNAL].width,
1487 sunxi.interfaces[DISPLAY_INTERNAL].height,
1488 DRM_FORMAT_BGRA8888,
1492 dev_err(sunxi.dev, "Failed to init ADF fbdev (%d)\n", err);
1493 goto err_free_ion_client;
1497 sunxi.debugfs_config_file = debugfs_create_file("adf_debug", S_IRUGO,
1498 NULL, NULL, &adf_sunxi_debugfs_fops);
1500 sunxi.debugfs_val_log = debugfs_create_file("adf_val_log", S_IRUGO,
1501 NULL, NULL, &adf_sunxi_debugfs_val_fops);
1502 dev_err(sunxi.dev, "Successfully loaded adf_sunxi\n");
1505 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1506 err_free_ion_client:
1508 ion_client_destroy(sunxi.ion_client);
1510 for (; dpy > 0; dpy--) {
1511 if (sunxi.interfaces[dpy-1].disp_type == DISP_OUTPUT_TYPE_NONE)
1513 for (; ovl > 0; ovl--) {
1514 adf_overlay_engine_destroy(
1515 &sunxi.overlays[dpy-1][ovl-1].overlay);
1519 for (; dpy > 0; dpy--) {
1520 if (sunxi.interfaces[dpy-1].disp_type == DISP_OUTPUT_TYPE_NONE)
1522 if (sunxi.interfaces[dpy-1].disp_type == DISP_OUTPUT_TYPE_HDMI)
1523 adf_sunxi_set_hotplug_state(&sunxi.interfaces[dpy],
1525 adf_interface_destroy(&sunxi.interfaces[dpy-1].interface);
1527 adf_device_destroy(&sunxi.device);
1529 debugfs_remove(sunxi.debugfs_config_file);
1530 sunxi.debugfs_config_file = NULL;
1531 debugfs_remove(sunxi.debugfs_val_log);
1532 sunxi.debugfs_val_log = NULL;
1536 static int adf_sunxi_remove(struct platform_device *pdev)
1540 #ifdef SUPPORT_ADF_SUNXI_FBDEV
1541 adf_fbdev_destroy(&sunxi.fbdev);
1543 debugfs_remove(sunxi.debugfs_config_file);
1544 sunxi.debugfs_config_file = NULL;
1545 debugfs_remove(sunxi.debugfs_val_log);
1546 sunxi.debugfs_val_log = NULL;
1547 ion_client_destroy(sunxi.ion_client);
1548 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
1549 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_NONE)
1551 for (ovl = 0; ovl < NUM_OVERLAYS; ovl++)
1552 adf_overlay_engine_destroy(
1553 &sunxi.overlays[dpy][ovl].overlay);
1555 for (dpy = 0; dpy < MAX_DISPLAYS; dpy++) {
1556 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_NONE)
1558 if (sunxi.interfaces[dpy].disp_type == DISP_OUTPUT_TYPE_HDMI)
1559 adf_sunxi_set_hotplug_state(&sunxi.interfaces[dpy],
1561 adf_interface_destroy(&sunxi.interfaces[dpy].interface);
1563 adf_device_destroy(&sunxi.device);
1567 static void adf_sunxi_device_release(struct device *dev)
1573 static int adf_sunxi_device_suspend(struct platform_device *pdev, pm_message_t state)
1577 static int adf_sunxi_device_resume(struct platform_device *pdev)
1582 struct platform_device adf_sunxi_platform_device =
1584 .name = "adf_sunxi",
1586 .dev.release = adf_sunxi_device_release,
1589 struct platform_driver adf_sunxi_platform_driver =
1591 .driver.name = "adf_sunxi",
1592 .probe = adf_sunxi_probe,
1593 .remove = adf_sunxi_remove,
1594 .suspend = adf_sunxi_device_suspend,
1595 .resume = adf_sunxi_device_resume,
1598 static int __init adf_sunxi_init(void)
1600 platform_device_register(&adf_sunxi_platform_device);
1601 platform_driver_register(&adf_sunxi_platform_driver);
1605 static void __exit adf_sunxi_exit(void)
1607 platform_device_unregister(&adf_sunxi_platform_device);
1608 platform_driver_unregister(&adf_sunxi_platform_driver);
1611 module_init(adf_sunxi_init);
1612 module_exit(adf_sunxi_exit);