1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdio.h>
29#include "include/bcm_host.h"
30#include "interface/vmcs_host/vc_dispmanx.h"
31#include "interface/vmcs_host/vc_vchi_gencmd.h"
32#include "interface/vmcs_host/vc_vchi_bufman.h"
33#include "interface/vmcs_host/vc_tvservice.h"
34#include "interface/vmcs_host/vc_cecservice.h"
35#include "interface/vchiq_arm/vchiq_if.h"
36
37static VCHI_INSTANCE_T global_initialise_instance;
38static VCHI_CONNECTION_T *global_connection;
39
40int32_t graphics_get_display_size( const uint16_t display_number,
41 uint32_t *width,
42 uint32_t *height)
43{
44 DISPMANX_DISPLAY_HANDLE_T display_handle = 0;
45 DISPMANX_MODEINFO_T mode_info;
46 int32_t success = -1;
47
48 // Display must be opened first.
49 display_handle = vc_dispmanx_display_open(display_number);
50
51 if (display_handle) {
52 success = vc_dispmanx_display_get_info(display_handle, &mode_info);
53
54 if( success >= 0 )
55 {
56 if( NULL != width )
57 {
58 *width = mode_info.width;
59 }
60
61 if( NULL != height )
62 {
63 *height = mode_info.height;
64 }
65 }
66 vc_dispmanx_display_close(display_handle);
67 display_handle = 0;
68 }
69
70 return success;
71}
72
73void host_app_message_handler(void)
74{
75 printf("host_app_message_handler\n");
76}
77
78void vc_host_get_vchi_state(VCHI_INSTANCE_T *initialise_instance, VCHI_CONNECTION_T **connection)
79{
80 if (initialise_instance) *initialise_instance = global_initialise_instance;
81 if (connection) *connection = global_connection;
82}
83
84void bcm_host_init(void)
85{
86 VCHIQ_INSTANCE_T vchiq_instance;
87 static int initted;
88 int success = -1;
89 char response[ 128 ];
90
91 if (initted)
92 return;
93 initted = 1;
94 vcos_init();
95
96 if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
97 {
98 printf("* failed to open vchiq instance\n");
99 exit(-1);
100 }
101
102 vcos_log("vchi_initialise");
103 success = vchi_initialise( &global_initialise_instance);
104 vcos_assert(success == 0);
105 vchiq_instance = (VCHIQ_INSTANCE_T)global_initialise_instance;
106
107 global_connection = vchi_create_connection(single_get_func_table(),
108 vchi_mphi_message_driver_func_table());
109
110 vcos_log("vchi_connect");
111 vchi_connect(&global_connection, 1, global_initialise_instance);
112
113 vc_vchi_gencmd_init (global_initialise_instance, &global_connection, 1);
114 vc_vchi_dispmanx_init (global_initialise_instance, &global_connection, 1);
115 vc_vchi_tv_init (global_initialise_instance, &global_connection, 1);
116 vc_vchi_cec_init (global_initialise_instance, &global_connection, 1);
117 //vc_vchi_bufman_init (global_initialise_instance, &global_connection, 1);
118
119 if ( success == 0 )
120 {
121 success = vc_gencmd( response, sizeof(response), "set_vll_dir /sd/vlls" );
122 vcos_assert( success == 0 );
123 }
124}
125
126void bcm_host_deinit(void)
127{
128}
129
130// Fix linking problems. These are referenced by libs, but shouldn't be called
131void wfc_stream_await_buffer(void * stream)
132{
133 vcos_assert(0);
134}
135
136static unsigned get_dt_ranges(const char *filename, unsigned offset)
137{
138 unsigned address = ~0;
139 FILE *fp = fopen(filename, "rb");
140 if (fp)
141 {
142 unsigned char buf[4];
143 fseek(fp, offset, SEEK_SET);
144 if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
145 address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
146 fclose(fp);
147 }
148 return address;
149}
150
151unsigned bcm_host_get_peripheral_address(void)
152{
153 unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
154 if (address == 0)
155 address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
156 return address == ~0 ? 0x20000000 : address;
157}
158
159unsigned bcm_host_get_peripheral_size(void)
160{
161 unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
162 address = get_dt_ranges("/proc/device-tree/soc/ranges", (address == 0) ? 12 : 8);
163 return address == ~0 ? 0x01000000 : address;
164}
165
166unsigned bcm_host_get_sdram_address(void)
167{
168 unsigned address = get_dt_ranges("/proc/device-tree/axi/vc_mem/reg", 8);
169 return address == ~0 ? 0x40000000 : address;
170}
171
172static int read_string_from_file(const char *filename, const char *format, unsigned int *value)
173{
174 FILE *fin;
175 char str[256];
176 int found = 0;
177
178 fin = fopen(filename, "rt");
179
180 if (fin == NULL)
181 return 0;
182
183 while (fgets(str, sizeof(str), fin) != NULL)
184 {
185 if (value)
186 {
187 if (sscanf(str, format, value) == 1)
188 {
189 found = 1;
190 break;
191 }
192 }
193 else
194 {
195 if (!strcmp(str, format))
196 {
197 found = 1;
198 break;
199 }
200 }
201 }
202
203 fclose(fin);
204
205 return found;
206}
207
208static unsigned int get_revision_code()
209{
210 static unsigned int revision_num = -1;
211 unsigned int num;
212 if (revision_num == -1 && read_string_from_file("/proc/cpuinfo", "Revision : %x", &num))
213 revision_num = num;
214 return revision_num;
215}
216
217/* Returns the type of the Pi being used
218*/
219int bcm_host_get_model_type(void)
220{
221 static int model_type = -1;
222 if (model_type != -1)
223 return model_type;
224 unsigned int revision_num = get_revision_code();
225
226 if (!revision_num)
227 model_type = 0;
228
229 // Check for old/new style revision code. Bit 23 will be guaranteed one for new style
230 else if (revision_num & 0x800000)
231 model_type = (revision_num & 0xff0) >> 4;
232 else
233 {
234 // Mask off warrantee and overclock bits.
235 revision_num &= 0xffffff;
236
237 // Map old style to new Type code
238 if (revision_num < 2 || revision_num > 21)
239 return 0;
240
241 static const unsigned char type_map[] =
242 {
243 1, // B rev 1.0 2
244 1, // B rev 1.0 3
245 1, // B rev 2.0 4
246 1, // B rev 2.0 5
247 1, // B rev 2.0 6
248 0, // A rev 2 7
249 0, // A rev 2 8
250 0, // A rev 2 9
251 0, 0, 0, // unused a,b,c
252 1, // B rev 2.0 d
253 1, // B rev 2.0 e
254 1, // B rev 2.0 f
255 3, // B+ rev 1.2 10
256 6, // CM1 11
257 2, // A+ rev1.1 12
258 3, // B+ rev 1.2 13
259 6, // CM1 14
260 2 // A+ 15
261 };
262 model_type = type_map[revision_num-2];
263 }
264
265 return model_type;
266}
267
268/* Returns the type of the Pi being used
269*/
270int bcm_host_is_model_pi4(void)
271{
272 return bcm_host_get_model_type() == 0x11 ? 1 : 0;
273}
274
275/* returns the processor ID
276*/
277int bcm_host_get_processor_id(void)
278{
279 unsigned int revision_num = get_revision_code();
280
281 if (revision_num & 0x800000)
282 {
283 return (revision_num & 0xf000) >> 12;
284 }
285 else
286 {
287 // Old style number only used 2835
288 return BCM_HOST_PROCESSOR_BCM2835;
289 }
290}
291
292
293static int bcm_host_is_fkms_or_kms_active(int kms)
294{
295 if (!read_string_from_file("/proc/device-tree/soc/v3d@7ec00000/status", "okay", NULL) &&
296 !read_string_from_file("/proc/device-tree/v3dbus/v3d@7ec04000/status", "okay", NULL))
297 return 0;
298 else
299 return read_string_from_file("/proc/device-tree/soc/firmwarekms@7e600000/status", "okay", NULL) ^ kms;
300}
301
302int bcm_host_is_fkms_active(void)
303{
304 static int active = -1;
305 if (active == -1)
306 active = bcm_host_is_fkms_or_kms_active(0);
307 return active;
308}
309
310int bcm_host_is_kms_active(void)
311{
312 static int active = -1;
313 if (active == -1)
314 active = bcm_host_is_fkms_or_kms_active(1);
315 return active;
316}
317