1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 #include <linux/kernel.h>
12 #include "disp_device.h"
13
14 static LIST_HEAD(device_list);
15
disp_device_set_manager(struct disp_device * dispdev,struct disp_manager * mgr)16 s32 disp_device_set_manager(struct disp_device *dispdev,
17 struct disp_manager *mgr)
18 {
19 if ((dispdev == NULL) || (mgr == NULL)) {
20 DE_WRN("NULL hdl!\n");
21 return DIS_FAIL;
22 }
23 DE_INF("device %d, mgr %d\n", dispdev->disp, mgr->disp);
24
25 dispdev->manager = mgr;
26 mgr->device = dispdev;
27
28 return DIS_SUCCESS;
29 }
30
disp_device_unset_manager(struct disp_device * dispdev)31 s32 disp_device_unset_manager(struct disp_device *dispdev)
32 {
33 if (dispdev == NULL) {
34 DE_WRN("NULL hdl!\n");
35 return DIS_FAIL;
36 }
37
38 if (dispdev->manager)
39 dispdev->manager->device = NULL;
40 dispdev->manager = NULL;
41
42 return DIS_SUCCESS;
43 }
44
disp_device_get_resolution(struct disp_device * dispdev,u32 * xres,u32 * yres)45 s32 disp_device_get_resolution(struct disp_device *dispdev, u32 *xres,
46 u32 *yres)
47 {
48 if (dispdev == NULL) {
49 DE_WRN("NULL hdl!\n");
50 return DIS_FAIL;
51 }
52
53 *xres = dispdev->timings.x_res;
54 *yres = dispdev->timings.y_res;
55
56 return 0;
57 }
58
disp_device_get_timings(struct disp_device * dispdev,struct disp_video_timings * timings)59 s32 disp_device_get_timings(struct disp_device *dispdev,
60 struct disp_video_timings *timings)
61 {
62 if (dispdev == NULL) {
63 DE_WRN("NULL hdl!\n");
64 return DIS_FAIL;
65 }
66
67 if (timings)
68 memcpy(timings, &dispdev->timings,
69 sizeof(struct disp_video_timings));
70
71 return 0;
72 }
73
disp_device_is_interlace(struct disp_device * dispdev)74 s32 disp_device_is_interlace(struct disp_device *dispdev)
75 {
76 if (dispdev == NULL) {
77 DE_WRN("NULL hdl!\n");
78 return DIS_FAIL;
79 }
80
81 return dispdev->timings.b_interlace;
82 }
83
disp_device_get_status(struct disp_device * dispdev)84 s32 disp_device_get_status(struct disp_device *dispdev)
85 {
86 if (dispdev == NULL) {
87 DE_WRN("NULL hdl!\n");
88 return 0;
89 }
90
91 return disp_al_device_get_status(dispdev->hwdev_index);
92 }
93
disp_device_is_in_safe_period(struct disp_device * dispdev)94 bool disp_device_is_in_safe_period(struct disp_device *dispdev)
95 {
96 int cur_line;
97 int start_delay;
98 bool ret = true;
99
100 if (dispdev == NULL) {
101 DE_WRN("NULL hdl!\n");
102 goto exit;
103 }
104
105 start_delay = disp_al_device_get_start_delay(dispdev->hwdev_index);
106 cur_line = disp_al_device_get_cur_line(dispdev->hwdev_index);
107 if (cur_line >= start_delay)
108 ret = false;
109
110 exit:
111 return ret;
112 }
113
disp_device_show_builtin_patten(struct disp_device * dispdev,u32 patten)114 void disp_device_show_builtin_patten(struct disp_device *dispdev, u32 patten)
115 {
116 if (dispdev)
117 disp_al_show_builtin_patten(dispdev->hwdev_index, patten);
118 }
119
disp_device_usec_before_vblank(struct disp_device * dispdev)120 u32 disp_device_usec_before_vblank(struct disp_device *dispdev)
121 {
122 int cur_line;
123 int start_delay;
124 u32 usec = 0;
125 struct disp_video_timings *timings;
126 u32 usec_per_line;
127 unsigned long long n_temp, base_temp;
128 u32 mod;
129
130 if (dispdev == NULL) {
131 DE_WRN("NULL hdl!\n");
132 goto exit;
133 }
134
135 start_delay = disp_al_device_get_start_delay(dispdev->hwdev_index);
136 cur_line = disp_al_device_get_cur_line(dispdev->hwdev_index);
137 if (cur_line > (start_delay - 4)) {
138 timings = &dispdev->timings;
139 n_temp = (unsigned long long)timings->hor_total_time *
140 (unsigned long long)(1000000);
141 base_temp = (unsigned long long)timings->pixel_clk;
142 mod = (u32)do_div(n_temp, base_temp);
143 usec_per_line = (u32)n_temp;
144 usec = (timings->ver_total_time - cur_line + 1) * usec_per_line;
145 }
146
147 exit:
148 return usec;
149 }
150
151 /* get free device */
disp_device_get(int disp,enum disp_output_type output_type)152 struct disp_device *disp_device_get(int disp, enum disp_output_type output_type)
153 {
154 struct disp_device *dispdev = NULL;
155
156 list_for_each_entry(dispdev, &device_list, list) {
157 if ((dispdev->type == output_type) && (dispdev->disp == disp)
158 && (dispdev->manager == NULL)) {
159 return dispdev;
160 }
161 }
162
163 return NULL;
164 }
165
166 /**
167 * @name :disp_device_get_from_priv
168 * @brief :get disp_device by comparing pointer of priv_data
169 * @param[IN] :priv_data:pointer of private date of disp_device
170 * @return :pointer of disp_device; NULL if not found
171 */
disp_device_get_from_priv(void * priv_data)172 struct disp_device *disp_device_get_from_priv(void *priv_data)
173 {
174 struct disp_device *dispdev = NULL;
175
176 list_for_each_entry(dispdev, &device_list, list) {
177 if (dispdev->priv_data == priv_data)
178 return dispdev;
179 }
180
181 return NULL;
182 }
183
disp_device_find(int disp,enum disp_output_type output_type)184 struct disp_device *disp_device_find(int disp,
185 enum disp_output_type output_type)
186 {
187 struct disp_device *dispdev = NULL;
188
189 list_for_each_entry(dispdev, &device_list, list) {
190 if ((dispdev->type == output_type) && (dispdev->disp == disp))
191 return dispdev;
192 }
193
194 return NULL;
195 }
196
disp_device_get_list_head(void)197 struct list_head *disp_device_get_list_head(void)
198 {
199 return &device_list;
200 }
201
disp_device_register(struct disp_device * dispdev)202 s32 disp_device_register(struct disp_device *dispdev)
203 {
204 list_add_tail(&dispdev->list, &device_list);
205 return 0;
206 }
207
disp_device_unregister(struct disp_device * dispdev)208 s32 disp_device_unregister(struct disp_device *dispdev)
209 {
210 list_del(&dispdev->list);
211 return 0;
212 }
213