Ticket #3846: 0001-Intel_extreme-i855g-support-3846.patch
File 0001-Intel_extreme-i855g-support-3846.patch, 18.6 KB (added by , 11 years ago) |
---|
-
headers/private/graphics/intel_extreme/intel_extreme.h
From 5819a94c7a7e6ecf4a529b56d0ca0892af135fd7 Mon Sep 17 00:00:00 2001 From: Adrien Destugues <pulkomandy@pulkomandy.tk> Date: Fri, 17 Jan 2014 10:55:03 +0100 Subject: [PATCH] Intel_extreme i855g support (#3846) Convert proposed patch into git more suitable git format and rebase against latest version of driver. https://github.com/druga/haiku-stuff/tree/master/intel_extreme --- .../private/graphics/intel_extreme/intel_extreme.h | 3 + src/add-ons/accelerants/intel_extreme/mode.cpp | 122 ++++++--- .../kernel/drivers/graphics/intel_extreme/Jamfile | 1 + .../kernel/drivers/graphics/intel_extreme/bios.cpp | 298 +++++++++++++++++++++ .../graphics/intel_extreme/intel_extreme.cpp | 6 + 5 files changed, 399 insertions(+), 31 deletions(-) create mode 100644 src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp diff --git a/headers/private/graphics/intel_extreme/intel_extreme.h b/headers/private/graphics/intel_extreme/intel_extreme.h index b8e969f..7c4c957 100644
a b struct intel_shared_info { 173 173 addr_t frame_buffer; 174 174 uint32 frame_buffer_offset; 175 175 176 bool got_vbt; 177 bool single_head_locked; 178 176 179 struct lock accelerant_lock; 177 180 struct lock engine_lock; 178 181 -
src/add-ons/accelerants/intel_extreme/mode.cpp
diff --git a/src/add-ons/accelerants/intel_extreme/mode.cpp b/src/add-ons/accelerants/intel_extreme/mode.cpp index 00182b8..f484863 100644
a b struct pll_limits { 74 74 }; 75 75 76 76 77 static struct display_mode_hook { 78 bool active; 79 display_mode *dm; 80 struct { 81 uint16 width; 82 uint16 height; 83 uint16 space; 84 } mode; 85 } display_mode_hook; 86 87 88 static void mode_fill_missing_bits(display_mode *, uint32); 89 90 77 91 static status_t 78 92 get_i2c_signals(void* cookie, int* _clock, int* _data) 79 93 { … … compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors, 283 297 284 298 285 299 static void 300 mode_fill_missing_bits(display_mode *mode, uint32 cntrl) 301 { 302 uint32 value = read32(cntrl); 303 304 switch (value & DISPLAY_CONTROL_COLOR_MASK) { 305 case DISPLAY_CONTROL_RGB32: 306 default: 307 mode->space = B_RGB32; 308 break; 309 case DISPLAY_CONTROL_RGB16: 310 mode->space = B_RGB16; 311 break; 312 case DISPLAY_CONTROL_RGB15: 313 mode->space = B_RGB15; 314 break; 315 case DISPLAY_CONTROL_CMAP8: 316 mode->space = B_CMAP8; 317 break; 318 } 319 320 mode->flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS; 321 } 322 323 324 static void 286 325 retrieve_current_mode(display_mode& mode, uint32 pllRegister) 287 326 { 288 327 uint32 pll = read32(pllRegister); … … retrieve_current_mode(display_mode& mode, uint32 pllRegister) 411 450 if (mode.virtual_height < mode.timing.v_display) 412 451 mode.virtual_height = mode.timing.v_display; 413 452 414 value = read32(controlRegister); 415 switch (value & DISPLAY_CONTROL_COLOR_MASK) { 416 case DISPLAY_CONTROL_RGB32: 417 default: 418 mode.space = B_RGB32; 419 break; 420 case DISPLAY_CONTROL_RGB16: 421 mode.space = B_RGB16; 422 break; 423 case DISPLAY_CONTROL_RGB15: 424 mode.space = B_RGB15; 425 break; 426 case DISPLAY_CONTROL_CMAP8: 427 mode.space = B_CMAP8; 428 break; 429 } 453 mode_fill_missing_bits(&mode, controlRegister); 430 454 431 455 mode.h_display_start = 0; 432 456 mode.v_display_start = 0; 433 mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS434 | B_DPMS;435 457 if (gInfo->overlay_registers != NULL) { 436 458 mode.flags |= B_SUPPORTS_OVERLAYS; 437 459 } … … set_frame_buffer_base() 535 557 uint32 baseRegister; 536 558 uint32 surfaceRegister; 537 559 538 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { 539 baseRegister = INTEL_DISPLAY_A_BASE; 540 surfaceRegister = INTEL_DISPLAY_A_SURFACE; 541 } else { 560 if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) { 542 561 baseRegister = INTEL_DISPLAY_B_BASE; 543 562 surfaceRegister = INTEL_DISPLAY_B_SURFACE; 563 } else { 564 baseRegister = INTEL_DISPLAY_A_BASE; 565 surfaceRegister = INTEL_DISPLAY_A_SURFACE; 544 566 } 545 567 546 568 if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x) … … create_mode_list(void) 578 600 if (error == B_OK) { 579 601 edid_dump(&gInfo->edid_info); 580 602 gInfo->has_edid = true; 603 if (gInfo->shared_info->single_head_locked) 604 gInfo->head_mode = HEAD_MODE_A_ANALOG; 581 605 } else { 582 606 TRACE("getting EDID on port A (analog) failed : %s. " 583 607 "Trying on port C (lvds)\n", strerror(error)); … … create_mode_list(void) 593 617 // We could not read any EDID info. Fallback to creating a list with 594 618 // only the mode set up by the BIOS. 595 619 // TODO: support lower modes via scaling and windowing 596 if ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 597 && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) { 620 if (((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 621 && (gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0) 622 || ((gInfo->head_mode & HEAD_MODE_LVDS_PANEL) != 0 623 && gInfo->shared_info->got_vbt)) { 598 624 size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) 599 625 & ~(B_PAGE_SIZE - 1); 600 626 … … create_mode_list(void) 605 631 if (area < B_OK) 606 632 return area; 607 633 608 memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode)); 634 // Prefer information dumped directly from VBT, as the BIOS 635 // one may have display scaling, but only do this if the VBT 636 // resolution is higher than the BIOS one. 637 if (gInfo->shared_info->got_vbt 638 && gInfo->shared_info->current_mode.virtual_width 639 >= gInfo->lvds_panel_mode.virtual_width 640 && gInfo->shared_info->current_mode.virtual_height 641 >= gInfo->lvds_panel_mode.virtual_height) { 642 memcpy(list, &gInfo->shared_info->current_mode, 643 sizeof(display_mode)); 644 mode_fill_missing_bits(list, INTEL_DISPLAY_B_CONTROL); 645 } else { 646 memcpy(list, &gInfo->lvds_panel_mode, 647 sizeof(display_mode)); 648 649 if (gInfo->shared_info->got_vbt) 650 TRACE("intel_extreme: ignoring VBT mode."); 651 } 652 653 // We can also make this the default resolution, if the user 654 // didn't pick one yet. 655 display_mode_hook.active = true; 656 display_mode_hook.dm = list; 609 657 610 658 gInfo->mode_list_area = area; 611 659 gInfo->mode_list = list; … … intel_propose_display_mode(display_mode* target, const display_mode* low, 717 765 status_t 718 766 intel_set_display_mode(display_mode* mode) 719 767 { 720 TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, 721 mode->virtual_width, mode->virtual_height); 768 if (display_mode_hook.active) { 769 mode = display_mode_hook.dm; 770 display_mode_hook.active = false; 771 } 722 772 723 773 if (mode == NULL) 724 774 return B_BAD_VALUE; 725 775 776 TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, 777 mode->virtual_width, mode->virtual_height); 778 726 779 display_mode target = *mode; 727 780 728 781 // TODO: it may be acceptable to continue when using panel fitting or … … intel_set_display_mode(display_mode* mode) 736 789 uint32 colorMode, bytesPerRow, bitsPerPixel; 737 790 get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); 738 791 739 // TODO: do not go further if the mode is identical to the current one. 740 // This would avoid the screen being off when switching workspaces when they 741 // have the same resolution. 792 // avoid screen being off when switching workspaces when they have the same 793 // resolution. 794 if (target.virtual_width == display_mode_hook.mode.width 795 && target.virtual_height == display_mode_hook.mode.height 796 && target.space == display_mode_hook.mode.space) 797 return B_OK; 742 798 743 799 #if 0 744 static bool first = tru e;800 static bool first = tru; 745 801 if (first) { 746 802 int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644); 747 803 if (fd >= 0) { … … if (first) { 1174 1230 sharedInfo.current_mode = target; 1175 1231 sharedInfo.bits_per_pixel = bitsPerPixel; 1176 1232 1233 display_mode_hook.mode.width = target.virtual_width; 1234 display_mode_hook.mode.height = target.virtual_height; 1235 display_mode_hook.mode.space = target.space; 1236 1177 1237 return B_OK; 1178 1238 } 1179 1239 -
src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile
diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile b/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile index 95bad2c..8ac97c6 100644
a b UsePrivateHeaders graphics kernel ; 8 8 UsePrivateHeaders shared ; 9 9 10 10 KernelAddon intel_extreme : 11 bios.cpp 11 12 driver.cpp 12 13 device.cpp 13 14 intel_extreme.cpp -
new file src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp
diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/bios.cpp new file mode 100644 index 0000000..f629928
- + 1 /* Written by Artem Falcon <lomka@gero.in> */ 2 3 #include <KernelExport.h> 4 #include "intel_extreme.h" 5 #include <string.h> 6 7 #define TRACE_BIOS 1 8 #ifdef TRACE_BIOS 9 # define TRACE(x) dprintf x 10 #else 11 # define TRACE(x) ; 12 #endif 13 14 /* for moving into intel_extreme_private.h */ 15 #define VBIOS 0xc0000 16 #define INTEL_VBIOS_SIZE (64 * 1024) /* XXX */ 17 18 #define INTEL_BIOS_16(_addr) (vbios.memory[_addr] | \ 19 (vbios.memory[_addr + 1] << 8)) 20 /* */ 21 22 /* subject of including into private/graphics/common/edid* */ 23 #define _PIXEL_CLOCK_MHZ(x) (x[0] + (x[1] << 8)) / 100 24 25 #define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 26 #define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) 27 #define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) 28 #define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) 29 #define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) 30 #define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) 31 #define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) 32 #define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) 33 #define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) 34 /* */ 35 36 struct vbt_header { 37 uint8 signature[20]; 38 uint16 version; 39 uint16 header_size; 40 uint16 vbt_size; 41 uint8 vbt_checksum; 42 uint8 reserved0; 43 uint32 bdb_offset; 44 uint32 aim_offset[4]; 45 } __attribute__((packed)); 46 47 struct bdb_header { 48 uint8 signature[16]; 49 uint16 version; 50 uint16 header_size; 51 uint16 bdb_size; 52 /* cutted */ 53 } __attribute__((packed)); 54 55 struct lvds_bdb1 { 56 uint8 id; 57 uint16 size; 58 uint8 panel_type; 59 uint8 reserved0; 60 uint16 caps; 61 } __attribute__((packed)); 62 63 struct lvds_bdb2_entry { 64 uint16 lfp_info_offset; 65 uint8 lfp_info_size; 66 uint16 lfp_edid_dtd_offset; 67 uint8 lfp_edid_dtd_size; 68 uint16 lfp_edid_pid_offset; 69 uint8 lfp_edid_pid_size; 70 } __attribute__((packed)); 71 72 struct lvds_bdb2 { 73 uint8 id; 74 uint16 size; 75 uint8 table_size; /* unapproved */ 76 struct lvds_bdb2_entry panels[16]; 77 } __attribute__((packed)); 78 79 struct lvds_bdb2_lfp_info { 80 uint16 x_res; 81 uint16 y_res; 82 uint32 lvds_reg; 83 uint32 lvds_reg_val; 84 uint32 pp_on_reg; 85 uint32 pp_on_reg_val; 86 uint32 pp_off_reg; 87 uint32 pp_off_reg_val; 88 uint32 pp_cycle_reg; 89 uint32 pp_cycle_reg_val; 90 uint32 pfit_reg; 91 uint32 pfit_reg_val; 92 uint16 terminator; 93 } __attribute__((packed)); 94 95 static struct vbios { 96 area_id area; 97 uint8* memory; 98 display_mode *shared_info; 99 struct { 100 uint16 hsync_start; 101 uint16 hsync_end; 102 uint16 hsync_total; 103 uint16 vsync_start; 104 uint16 vsync_end; 105 uint16 vsync_total; 106 } timings_common; 107 } vbios; 108 109 static inline bool unmap_bios(area_id area, uint8* mem) { 110 delete_area(area); 111 mem = NULL; 112 113 return false; 114 } 115 116 /* TO-DO: move to accelerant code, if possible */ 117 118 /* this is reimplementation, Haiku uses BIOS call and gets most 119 * current panel info, we're, otherwise, digging in VBIOS memory 120 * and parsing VBT tables to get native panel timings. This will 121 * allow to get non-updated, PROM-programmed timings info when 122 * compensation mode is off on your machine */ 123 static bool 124 get_bios(void) 125 { 126 int vbt_offset; 127 struct vbt_header *vbt; 128 129 /* !!!DANGER!!!: mapping of BIOS using legacy location for now, 130 * hence, if panel mode will be set using info from VBT, it will 131 * be taken from primary card's VBIOS */ 132 vbios.area = map_physical_memory("VBIOS mapping", 133 VBIOS, INTEL_VBIOS_SIZE, B_ANY_KERNEL_ADDRESS, 134 B_READ_AREA, (void**)&(vbios.memory)); 135 136 if (vbios.area < 0) 137 return false; 138 139 TRACE((DEVICE_NAME ": mapping VBIOS: 0x%x -> %p\n", 140 VBIOS, vbios.memory)); 141 142 vbt_offset = INTEL_BIOS_16(0x1a); 143 if (vbt_offset >= INTEL_VBIOS_SIZE) { 144 TRACE(("intel_extreme: bad VBT offset : 0x%x\n", 145 vbt_offset)); 146 return unmap_bios(vbios.area, vbios.memory); 147 } 148 149 vbt = (struct vbt_header *)(vbios.memory + vbt_offset); 150 if (memcmp(vbt->signature, "$VBT", 4) != 0) { 151 TRACE(("intel_extreme: bad VBT signature: %20s\n", 152 vbt->signature)); 153 return unmap_bios(vbios.area, vbios.memory); 154 } 155 156 return true; 157 } 158 159 static bool feed_shared_info(uint8* data) 160 { 161 bool bogus = false; 162 163 /* handle bogus h/vtotal values, if got such */ 164 if (vbios.timings_common.hsync_end > vbios.timings_common.hsync_total) { 165 vbios.timings_common.hsync_total = 166 vbios.timings_common.hsync_end + 1; 167 bogus = true; 168 TRACE(("intel_extreme: got bogus htotal. Fixing\n")); 169 } 170 if (vbios.timings_common.vsync_end > vbios.timings_common.vsync_total) { 171 vbios.timings_common.vsync_total = 172 vbios.timings_common.vsync_end + 1; 173 bogus = true; 174 TRACE(("intel_extreme: got bogus vtotal. Fixing\n")); 175 } 176 /* */ 177 if (bogus) 178 TRACE(("intel_extreme: adjusted LFP modeline: x%d Hz,\t%d " 179 "%d %d %d %d %d %d %d %d\n", 180 _PIXEL_CLOCK(data) / ( 181 (_H_ACTIVE(data) + _H_BLANK(data)) 182 * (_V_ACTIVE(data) + _V_BLANK(data)) 183 ), 184 _PIXEL_CLOCK_MHZ(data), 185 _H_ACTIVE(data), vbios.timings_common.hsync_start, 186 vbios.timings_common.hsync_end, vbios.timings_common.hsync_total, 187 _V_ACTIVE(data), vbios.timings_common.vsync_start, 188 vbios.timings_common.vsync_end, vbios.timings_common.vsync_total 189 )); 190 191 /* TO-DO: add retrieved info to edid info struct, not fixed mode struct */ 192 193 /* struct display_timing is not packed, so we're end setting of every single elm of it */ 194 vbios.shared_info->timing.pixel_clock = _PIXEL_CLOCK(data) / 1000; 195 vbios.shared_info->timing.h_display = vbios.shared_info->virtual_width = _H_ACTIVE(data); 196 vbios.shared_info->timing.h_sync_start = vbios.timings_common.hsync_start; 197 vbios.shared_info->timing.h_sync_end = vbios.timings_common.hsync_end; 198 vbios.shared_info->timing.h_total = vbios.timings_common.hsync_total; 199 vbios.shared_info->timing.v_display = vbios.shared_info->virtual_height = _V_ACTIVE(data); 200 vbios.shared_info->timing.v_sync_start = vbios.timings_common.vsync_start; 201 vbios.shared_info->timing.v_sync_end = vbios.timings_common.vsync_end; 202 vbios.shared_info->timing.v_total = vbios.timings_common.vsync_total; 203 204 unmap_bios(vbios.area, vbios.memory); 205 return true; 206 } 207 208 bool get_lvds_mode_from_bios(display_mode *shared_info) 209 { 210 struct vbt_header *vbt; 211 struct bdb_header *bdb; 212 int vbt_offset, bdb_offset, bdb_block_offset, block_size; 213 int panel_type = -1; 214 215 if (!get_bios()) 216 return false; 217 218 vbt_offset = INTEL_BIOS_16(0x1a); 219 vbt = (struct vbt_header *)(vbios.memory + vbt_offset); 220 bdb_offset = vbt_offset + vbt->bdb_offset; 221 222 bdb = (struct bdb_header *)(vbios.memory + bdb_offset); 223 if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { 224 TRACE(("intel_extreme: bad BDB signature\n")); 225 return unmap_bios(vbios.area, vbios.memory); 226 } 227 228 TRACE(("intel_extreme: parsing BDB blocks\n")); 229 for (bdb_block_offset = bdb->header_size; bdb_block_offset < bdb->bdb_size; 230 bdb_block_offset += block_size) { 231 int start = bdb_offset + bdb_block_offset; 232 int id; 233 struct lvds_bdb1 *lvds1; 234 struct lvds_bdb2 *lvds2; 235 struct lvds_bdb2_lfp_info *lvds2_lfp_info; 236 uint8_t *timing_data; 237 238 id = vbios.memory[start]; 239 block_size = INTEL_BIOS_16(start + 1) + 3; 240 //TRACE(("intel_extreme: found BDB block type %d\n", id)); 241 switch (id) { 242 case 40: 243 lvds1 = (struct lvds_bdb1 *)(vbios.memory + start); 244 panel_type = lvds1->panel_type; 245 break; 246 case 41: 247 if (panel_type == -1) 248 break; 249 lvds2 = (struct lvds_bdb2 *)(vbios.memory + start); 250 lvds2_lfp_info = (struct lvds_bdb2_lfp_info *) 251 (vbios.memory + bdb_offset + 252 lvds2->panels[panel_type].lfp_info_offset); 253 /* found bad one terminator */ 254 if (lvds2_lfp_info->terminator != 0xffff) { 255 return unmap_bios(vbios.area, vbios.memory); 256 } 257 timing_data = vbios.memory + bdb_offset + 258 lvds2->panels[panel_type].lfp_edid_dtd_offset; 259 TRACE(("intel_extreme: found LFP of size %d x %d " 260 "in BIOS VBT tables\n", 261 lvds2_lfp_info->x_res, lvds2_lfp_info->y_res)); 262 263 vbios.timings_common.hsync_start = _H_ACTIVE(timing_data) + 264 _H_SYNC_OFF(timing_data); 265 vbios.timings_common.hsync_end = vbios.timings_common.hsync_start 266 + _H_SYNC_WIDTH(timing_data); 267 vbios.timings_common.hsync_total = _H_ACTIVE(timing_data) + 268 _H_BLANK(timing_data); 269 vbios.timings_common.vsync_start = _V_ACTIVE(timing_data) + 270 _V_SYNC_OFF(timing_data); 271 vbios.timings_common.vsync_end = vbios.timings_common.vsync_start 272 + _V_SYNC_WIDTH(timing_data); 273 vbios.timings_common.vsync_total = _V_ACTIVE(timing_data) + 274 _V_BLANK(timing_data); 275 276 /* Xfree86 compatible modeline */ 277 /*TRACE(("intel_extreme: LFP modeline: x%d Hz,\t%d " 278 "%d %d %d %d %d %d %d %d\n", 279 _PIXEL_CLOCK(timing_data) / ( 280 (_H_ACTIVE(timing_data) + _H_BLANK(timing_data)) 281 * (_V_ACTIVE(timing_data) + _V_BLANK(timing_data)) 282 ), 283 _PIXEL_CLOCK_MHZ(timing_data), 284 _H_ACTIVE(timing_data), vbios.timings_common.hsync_start, 285 vbios.timings_common.hsync_end, vbios.timings_common.hsync_total, 286 _V_ACTIVE(timing_data), vbios.timings_common.vsync_start, 287 vbios.timings_common.vsync_end, vbios.timings_common.vsync_total 288 ));*/ 289 290 vbios.shared_info = shared_info; 291 return feed_shared_info(timing_data); 292 break; 293 } 294 } 295 296 unmap_bios(vbios.area, vbios.memory); 297 return true; 298 } -
src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp
diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index 9c087b7..5adb4b3 100644
a b intel_extreme_init(intel_info &info) 333 333 info.shared_info->frame_buffer = 0; 334 334 info.shared_info->dpms_mode = B_DPMS_ON; 335 335 336 info.shared_info->got_vbt = get_lvds_mode_from_bios( 337 &info.shared_info->current_mode); 338 /* at least 855gm can't drive more than one head at time */ 339 if (info.device_type.InFamily(INTEL_TYPE_8xx)) 340 info.shared_info->single_head_locked = 1; 341 336 342 if (info.device_type.InFamily(INTEL_TYPE_9xx)) { 337 343 info.shared_info->pll_info.reference_frequency = 96000; // 96 kHz 338 344 info.shared_info->pll_info.max_frequency = 400000;