| 1 | /* | 
|---|
| 2 | Copyright (c) 2012, Broadcom Europe Ltd | 
|---|
| 3 | All rights reserved. | 
|---|
| 4 |  | 
|---|
| 5 | Redistribution and use in source and binary forms, with or without | 
|---|
| 6 | modification, 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 |  | 
|---|
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
|---|
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
|---|
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
|---|
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY | 
|---|
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
|---|
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
|---|
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
|---|
| 23 | ON 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 | 
|---|
| 25 | SOFTWARE, 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 |  | 
|---|
| 37 | static VCHI_INSTANCE_T global_initialise_instance; | 
|---|
| 38 | static VCHI_CONNECTION_T *global_connection; | 
|---|
| 39 |  | 
|---|
| 40 | int32_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 |  | 
|---|
| 73 | void host_app_message_handler(void) | 
|---|
| 74 | { | 
|---|
| 75 | printf( "host_app_message_handler\n"); | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | void 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 |  | 
|---|
| 84 | void 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 |  | 
|---|
| 126 | void bcm_host_deinit(void) | 
|---|
| 127 | { | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | // Fix linking problems. These are referenced by libs, but shouldn't be called | 
|---|
| 131 | void wfc_stream_await_buffer(void * stream) | 
|---|
| 132 | { | 
|---|
| 133 | vcos_assert(0); | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | static 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 |  | 
|---|
| 151 | unsigned 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 |  | 
|---|
| 159 | unsigned 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 |  | 
|---|
| 166 | unsigned 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 |  | 
|---|
| 172 | static 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 |  | 
|---|
| 208 | static 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 | */ | 
|---|
| 219 | int 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 | */ | 
|---|
| 270 | int 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 | */ | 
|---|
| 277 | int 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 |  | 
|---|
| 293 | static 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 |  | 
|---|
| 302 | int 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 |  | 
|---|
| 310 | int 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 |  | 
|---|