1 /* 2 * Copyright (C) 2016 Nelson Integration, LLC 3 * Author: Eric Nelson <eric@nelint.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <asm/io.h> 10 #include <asm/arch/iomux.h> 11 #include <asm/arch/clock.h> 12 #include <asm/arch/crm_regs.h> 13 #include <asm/arch/mx6-ddr.h> 14 #include <asm/arch/mx6-pins.h> 15 #include <asm/arch/sys_proto.h> 16 #include <spl.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 #define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ 21 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \ 22 PAD_CTL_SRE_FAST | PAD_CTL_HYS) 23 24 static iomux_v3_cfg_t const uart_pads[] = { 25 #ifdef CONFIG_UART2_EIM_D26_27 26 IOMUX_PADS(PAD_EIM_D26__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 27 IOMUX_PADS(PAD_EIM_D27__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 28 #elif defined(CONFIG_UART1_CSI0_DAT10_11) 29 IOMUX_PADS(PAD_CSI0_DAT10__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 30 IOMUX_PADS(PAD_CSI0_DAT11__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 31 #elif defined(CONFIG_UART1_SD3_DAT6_7) 32 IOMUX_PADS(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 33 IOMUX_PADS(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 34 #elif defined(CONFIG_UART1_UART1) 35 MX6_PAD_UART1_TXD__UART1_TXD | MUX_PAD_CTRL(UART_PAD_CTRL), 36 MX6_PAD_UART1_RXD__UART1_RXD | MUX_PAD_CTRL(UART_PAD_CTRL), 37 #else 38 #error select UART console pads 39 #endif 40 }; 41 42 #ifdef CONFIG_DDR3 43 #define GRP_DDRTYPE 0x000C0000 44 #else 45 #define GRP_DDRTYPE 0x00080000 46 #endif 47 48 /* all existing designs have this disabled */ 49 #define DDR_PKE 0 50 51 /* use Kconfig for ODT and DRIVE_STRENGTH */ 52 #define DDR_ODT \ 53 (CONFIG_DDR_ODT << 8) 54 #define DRAM_DRIVE_STRENGTH \ 55 (CONFIG_DRAM_DRIVE_STRENGTH << 3) 56 57 /* configure MX6Q/DUAL mmdc DDR io registers */ 58 static struct mx6dq_iomux_ddr_regs const mx6dq_ddr_ioregs = { 59 /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ 60 .dram_sdclk_0 = DDR_ODT + DRAM_DRIVE_STRENGTH, 61 .dram_sdclk_1 = DDR_ODT + DRAM_DRIVE_STRENGTH, 62 .dram_cas = DDR_ODT + DRAM_DRIVE_STRENGTH, 63 .dram_ras = DDR_ODT + DRAM_DRIVE_STRENGTH, 64 .dram_reset = DDR_ODT + DRAM_DRIVE_STRENGTH, 65 /* SDCKE[0:1]: 100k pull-up */ 66 .dram_sdcke0 = 0x00003000, 67 .dram_sdcke1 = 0x00003000, 68 /* SDBA2: pull-up disabled */ 69 .dram_sdba2 = 0x00000000, 70 /* SDODT[0:1]: 100k pull-up, 40 ohm */ 71 .dram_sdodt0 = 0x00003000 + DRAM_DRIVE_STRENGTH, 72 .dram_sdodt1 = 0x00003000 + DRAM_DRIVE_STRENGTH, 73 /* SDQS[0:7]: Differential input, 40 ohm */ 74 .dram_sdqs0 = DRAM_DRIVE_STRENGTH, 75 .dram_sdqs1 = DRAM_DRIVE_STRENGTH, 76 .dram_sdqs2 = DRAM_DRIVE_STRENGTH, 77 .dram_sdqs3 = DRAM_DRIVE_STRENGTH, 78 .dram_sdqs4 = DRAM_DRIVE_STRENGTH, 79 .dram_sdqs5 = DRAM_DRIVE_STRENGTH, 80 .dram_sdqs6 = DRAM_DRIVE_STRENGTH, 81 .dram_sdqs7 = DRAM_DRIVE_STRENGTH, 82 83 /* DQM[0:7]: Differential input, 40 ohm */ 84 .dram_dqm0 = DDR_ODT + DRAM_DRIVE_STRENGTH, 85 .dram_dqm1 = DDR_ODT + DRAM_DRIVE_STRENGTH, 86 .dram_dqm2 = DDR_ODT + DRAM_DRIVE_STRENGTH, 87 .dram_dqm3 = DDR_ODT + DRAM_DRIVE_STRENGTH, 88 .dram_dqm4 = DDR_ODT + DRAM_DRIVE_STRENGTH, 89 .dram_dqm5 = DDR_ODT + DRAM_DRIVE_STRENGTH, 90 .dram_dqm6 = DDR_ODT + DRAM_DRIVE_STRENGTH, 91 .dram_dqm7 = DDR_ODT + DRAM_DRIVE_STRENGTH, 92 }; 93 94 /* configure MX6Q/DUAL mmdc GRP io registers */ 95 static struct mx6dq_iomux_grp_regs const mx6dq_grp_ioregs = { 96 /* DDR3 */ 97 .grp_ddr_type = GRP_DDRTYPE, 98 .grp_ddrmode_ctl = DDR_ODT, 99 /* disable DDR pullups */ 100 .grp_ddrpke = DDR_PKE, 101 /* ADDR[00:16], SDBA[0:1]: 40 ohm */ 102 .grp_addds = DRAM_DRIVE_STRENGTH, 103 /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ 104 .grp_ctlds = DRAM_DRIVE_STRENGTH, 105 /* DATA[00:63]: Differential input, 40 ohm */ 106 .grp_ddrmode = DDR_ODT, 107 .grp_b0ds = DRAM_DRIVE_STRENGTH, 108 .grp_b1ds = DRAM_DRIVE_STRENGTH, 109 .grp_b2ds = DRAM_DRIVE_STRENGTH, 110 .grp_b3ds = DRAM_DRIVE_STRENGTH, 111 .grp_b4ds = DRAM_DRIVE_STRENGTH, 112 .grp_b5ds = DRAM_DRIVE_STRENGTH, 113 .grp_b6ds = DRAM_DRIVE_STRENGTH, 114 .grp_b7ds = DRAM_DRIVE_STRENGTH, 115 }; 116 117 static struct mx6sdl_iomux_ddr_regs const mx6sdl_ddr_ioregs = { 118 /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ 119 .dram_sdclk_0 = DDR_ODT + DRAM_DRIVE_STRENGTH, 120 .dram_sdclk_1 = DDR_ODT + DRAM_DRIVE_STRENGTH, 121 .dram_cas = DDR_ODT + DRAM_DRIVE_STRENGTH, 122 .dram_ras = DDR_ODT + DRAM_DRIVE_STRENGTH, 123 .dram_reset = DDR_ODT + DRAM_DRIVE_STRENGTH, 124 /* SDCKE[0:1]: 100k pull-up */ 125 .dram_sdcke0 = 0x00003000, 126 .dram_sdcke1 = 0x00003000, 127 /* SDBA2: pull-up disabled */ 128 .dram_sdba2 = 0x00000000, 129 /* SDODT[0:1]: 100k pull-up, 40 ohm */ 130 .dram_sdodt0 = 0x00003000 + DRAM_DRIVE_STRENGTH, 131 .dram_sdodt1 = 0x00003000 + DRAM_DRIVE_STRENGTH, 132 /* SDQS[0:7]: Differential input, 40 ohm */ 133 .dram_sdqs0 = DRAM_DRIVE_STRENGTH, 134 .dram_sdqs1 = DRAM_DRIVE_STRENGTH, 135 .dram_sdqs2 = DRAM_DRIVE_STRENGTH, 136 .dram_sdqs3 = DRAM_DRIVE_STRENGTH, 137 .dram_sdqs4 = DRAM_DRIVE_STRENGTH, 138 .dram_sdqs5 = DRAM_DRIVE_STRENGTH, 139 .dram_sdqs6 = DRAM_DRIVE_STRENGTH, 140 .dram_sdqs7 = DRAM_DRIVE_STRENGTH, 141 142 /* DQM[0:7]: Differential input, 40 ohm */ 143 .dram_dqm0 = DDR_ODT + DRAM_DRIVE_STRENGTH, 144 .dram_dqm1 = DDR_ODT + DRAM_DRIVE_STRENGTH, 145 .dram_dqm2 = DDR_ODT + DRAM_DRIVE_STRENGTH, 146 .dram_dqm3 = DDR_ODT + DRAM_DRIVE_STRENGTH, 147 .dram_dqm4 = DDR_ODT + DRAM_DRIVE_STRENGTH, 148 .dram_dqm5 = DDR_ODT + DRAM_DRIVE_STRENGTH, 149 .dram_dqm6 = DDR_ODT + DRAM_DRIVE_STRENGTH, 150 .dram_dqm7 = DDR_ODT + DRAM_DRIVE_STRENGTH, 151 }; 152 153 /* configure MX6SOLO/DUALLITE mmdc GRP io registers */ 154 static struct mx6sdl_iomux_grp_regs const mx6sdl_grp_ioregs = { 155 /* DDR3 */ 156 .grp_ddr_type = GRP_DDRTYPE, 157 /* SDQS[0:7]: Differential input, 40 ohm */ 158 .grp_ddrmode_ctl = DDR_ODT, 159 /* disable DDR pullups */ 160 .grp_ddrpke = DDR_PKE, 161 /* ADDR[00:16], SDBA[0:1]: 40 ohm */ 162 .grp_addds = DRAM_DRIVE_STRENGTH, 163 /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ 164 .grp_ctlds = DRAM_DRIVE_STRENGTH, 165 /* DATA[00:63]: Differential input, 40 ohm */ 166 .grp_ddrmode = DDR_ODT, 167 .grp_b0ds = DRAM_DRIVE_STRENGTH, 168 .grp_b1ds = DRAM_DRIVE_STRENGTH, 169 .grp_b2ds = DRAM_DRIVE_STRENGTH, 170 .grp_b3ds = DRAM_DRIVE_STRENGTH, 171 .grp_b4ds = DRAM_DRIVE_STRENGTH, 172 .grp_b5ds = DRAM_DRIVE_STRENGTH, 173 .grp_b6ds = DRAM_DRIVE_STRENGTH, 174 .grp_b7ds = DRAM_DRIVE_STRENGTH, 175 }; 176 177 const struct mx6sl_iomux_ddr_regs mx6sl_ddr_ioregs = { 178 .dram_sdqs0 = DRAM_DRIVE_STRENGTH, 179 .dram_sdqs1 = DRAM_DRIVE_STRENGTH, 180 .dram_sdqs2 = DRAM_DRIVE_STRENGTH, 181 .dram_sdqs3 = DRAM_DRIVE_STRENGTH, 182 .dram_dqm0 = DRAM_DRIVE_STRENGTH, 183 .dram_dqm1 = DRAM_DRIVE_STRENGTH, 184 .dram_dqm2 = DRAM_DRIVE_STRENGTH, 185 .dram_dqm3 = DRAM_DRIVE_STRENGTH, 186 .dram_cas = DRAM_DRIVE_STRENGTH, 187 .dram_ras = DRAM_DRIVE_STRENGTH, 188 .dram_sdclk_0 = DRAM_DRIVE_STRENGTH, 189 .dram_reset = DRAM_DRIVE_STRENGTH, 190 .dram_sdba2 = 0x00020000, 191 .dram_odt0 = 0x00030000 + DRAM_DRIVE_STRENGTH, 192 .dram_odt1 = 0x00030000 + DRAM_DRIVE_STRENGTH, 193 }; 194 195 const struct mx6sl_iomux_grp_regs mx6sl_grp_ioregs = { 196 .grp_b0ds = DRAM_DRIVE_STRENGTH, 197 .grp_b1ds = DRAM_DRIVE_STRENGTH, 198 .grp_b2ds = DRAM_DRIVE_STRENGTH, 199 .grp_b3ds = DRAM_DRIVE_STRENGTH, 200 .grp_addds = DRAM_DRIVE_STRENGTH, 201 .grp_ctlds = DRAM_DRIVE_STRENGTH, 202 .grp_ddrmode_ctl = DDR_ODT, 203 .grp_ddrpke = DDR_PKE, 204 .grp_ddrmode = DDR_ODT, 205 .grp_ddr_type = GRP_DDRTYPE, 206 }; 207 208 static struct mx6_ddr_sysinfo const sysinfo = { 209 /* width of data bus:0=16,1=32,2=64 */ 210 #if CONFIG_DDRWIDTH == 32 211 .dsize = 1, 212 #elif CONFIG_DDRWIDTH == 64 213 .dsize = 2, 214 #else 215 #error missing CONFIG_DDRWIDTH 216 #endif 217 /* config for full 4GB range so that get_mem_size() works */ 218 .cs_density = 32, /* 32Gb per CS */ 219 220 /* # of chip selects */ 221 .ncs = CONFIG_DDRCS, 222 .cs1_mirror = 0, 223 .bi_on = 1, /* Bank interleaving enabled */ 224 .rtt_nom = CONFIG_RTT_NOM, 225 .rtt_wr = CONFIG_RTT_WR, 226 .ralat = CONFIG_RALAT, /* Read additional latency */ 227 .walat = CONFIG_WALAT, /* Write additional latency */ 228 .mif3_mode = 3, /* Command prediction working mode */ 229 #ifdef CONFIG_DDR3 230 .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ 231 .sde_to_rst = 0x10, /* JEDEC value for LPDDR2 - 200us */ 232 .pd_fast_exit = 0, /* immaterial for calibration */ 233 .ddr_type = DDR_TYPE_DDR3, 234 #else 235 .rst_to_cke = 0x10, /* JEDEC value for LPDDR2: 200us */ 236 .sde_to_rst = 0, /* LPDDR2 does not need this field */ 237 .pd_fast_exit = 0, /* immaterial for calibration */ 238 .ddr_type = DDR_TYPE_LPDDR2, 239 #endif 240 .refsel = CONFIG_REFSEL, 241 .refr = CONFIG_REFR, 242 }; 243 244 #ifdef CONFIG_MT41K512M16TNA 245 /* Micron MT41K512M16TNA-125 */ 246 static struct mx6_ddr3_cfg const ddrtype = { 247 .mem_speed = 1600, 248 .density = 8, 249 .width = 16, 250 .banks = 8, 251 .rowaddr = 15, 252 .coladdr = 10, 253 .pagesz = 1, 254 .trcd = 1375, 255 .trcmin = 5062, 256 .trasmin = 3750, 257 }; 258 #elif defined(CONFIG_MT41K128M16JT) 259 /* Micron MT41K128M16JT-125 */ 260 static struct mx6_ddr3_cfg const ddrtype = { 261 .mem_speed = 1600, 262 .density = 2, 263 .width = 16, 264 .banks = 8, 265 .rowaddr = 14, 266 .coladdr = 10, 267 .pagesz = 2, 268 .trcd = 1375, 269 .trcmin = 4875, 270 .trasmin = 3500, 271 }; 272 #elif defined(CONFIG_H5TQ4G63AFR) 273 /* Hynix H5TQ4G63AFR */ 274 static struct mx6_ddr3_cfg const ddrtype = { 275 .mem_speed = 1600, 276 .density = 4, 277 .width = 16, 278 .banks = 8, 279 .rowaddr = 15, 280 .coladdr = 10, 281 .pagesz = 2, 282 .trcd = 1375, 283 .trcmin = 4875, 284 .trasmin = 3500, 285 }; 286 #elif defined CONFIG_H5TQ2G63DFR 287 /* Hynix H5TQ2G63DFR */ 288 static struct mx6_ddr3_cfg const ddrtype = { 289 .mem_speed = 1333, 290 .density = 2, 291 .width = 16, 292 .banks = 8, 293 .rowaddr = 14, 294 .coladdr = 10, 295 .pagesz = 2, 296 .trcd = 1350, 297 .trcmin = 4950, 298 .trasmin = 3600, 299 }; 300 #elif defined(CONFIG_MT42L256M32D2LG) 301 /* Micron MT42L256M32D2LG */ 302 static struct mx6_lpddr2_cfg ddrtype = { 303 .mem_speed = 800, 304 .density = 4, 305 .width = 32, 306 .banks = 8, 307 .rowaddr = 14, 308 .coladdr = 10, 309 .trcd_lp = 2000, 310 .trppb_lp = 2000, 311 .trpab_lp = 2250, 312 .trasmin = 4200, 313 }; 314 #elif defined(CONFIG_MT29PZZZ4D4BKESK) 315 /* Micron MT29PZZZ4D4BKESK */ 316 static struct mx6_lpddr2_cfg ddrtype = { 317 .mem_speed = 800, 318 .density = 4, 319 .width = 32, 320 .banks = 8, 321 .rowaddr = 14, 322 .coladdr = 10, 323 .trcd_lp = 2000, 324 .trppb_lp = 2000, 325 .trpab_lp = 2250, 326 .trasmin = 4200, 327 }; 328 #else 329 #error please select DDR type using menuconfig 330 #endif 331 332 static void ccgr_init(void) 333 { 334 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; 335 336 /* FIXME: these should probably be checked, especially 337 * for i.MX6SL, UL, ULL 338 */ 339 writel(0x00C03F3F, &ccm->CCGR0); 340 writel(0x0030FC03, &ccm->CCGR1); 341 writel(0x0FFFC000, &ccm->CCGR2); 342 writel(0x3FF00000, &ccm->CCGR3); 343 writel(0x00FFF300, &ccm->CCGR4); 344 writel(0x0F0000C3, &ccm->CCGR5); 345 writel(0x000003FF, &ccm->CCGR6); 346 } 347 348 static void display_calibration(struct mx6_mmdc_calibration *calib) 349 { 350 printf(".p0_mpdgctrl0\t= 0x%08X\n", calib->p0_mpdgctrl0); 351 printf(".p0_mpdgctrl1\t= 0x%08X\n", calib->p0_mpdgctrl1); 352 printf(".p0_mprddlctl\t= 0x%08X\n", calib->p0_mprddlctl); 353 printf(".p0_mpwrdlctl\t= 0x%08X\n", calib->p0_mpwrdlctl); 354 printf(".p0_mpwldectrl0\t= 0x%08X\n", calib->p0_mpwldectrl0); 355 printf(".p0_mpwldectrl1\t= 0x%08X\n", calib->p0_mpwldectrl1); 356 if (sysinfo.dsize == 2) { 357 printf(".p1_mpdgctrl0\t= 0x%08X\n", calib->p1_mpdgctrl0); 358 printf(".p1_mpdgctrl1\t= 0x%08X\n", calib->p1_mpdgctrl1); 359 printf(".p1_mprddlctl\t= 0x%08X\n", calib->p1_mprddlctl); 360 printf(".p1_mpwrdlctl\t= 0x%08X\n", calib->p1_mpwrdlctl); 361 printf(".p1_mpwldectrl0\t= 0x%08X\n", calib->p1_mpwldectrl0); 362 printf(".p1_mpwldectrl1\t= 0x%08X\n", calib->p1_mpwldectrl1); 363 } 364 #ifdef CONFIG_IMXIMAGE_OUTPUT 365 printf("DATA 4 MX6_MMDC_P0_MPDGCTRL0\t= 0x%08X\n", calib->p0_mpdgctrl0); 366 printf("DATA 4 MX6_MMDC_P0_MPDGCTRL1\t= 0x%08X\n", calib->p0_mpdgctrl1); 367 printf("DATA 4 MX6_MMDC_P0_MPRDDLCTL\t= 0x%08X\n", calib->p0_mprddlctl); 368 printf("DATA 4 MX6_MMDC_P0_MPWRDLCTL\t= 0x%08X\n", calib->p0_mpwrdlctl); 369 printf("DATA 4 MX6_MMDC_P0_MPWLDECTRL0\t= 0x%08X\n", 370 calib->p0_mpwldectrl0); 371 printf("DATA 4 MX6_MMDC_P0_MPWLDECTRL1\t= 0x%08X\n", 372 calib->p0_mpwldectrl1); 373 if (sysinfo.dsize == 2) { 374 printf("DATA 4 MX6_MMDC_P1_MPDGCTRL0\t= 0x%08X\n", 375 calib->p1_mpdgctrl0); 376 printf("DATA 4 MX6_MMDC_P1_MPDGCTRL1\t= 0x%08X\n", 377 calib->p1_mpdgctrl1); 378 printf("DATA 4 MX6_MMDC_P1_MPRDDLCTL\t= 0x%08X\n", 379 calib->p1_mprddlctl); 380 printf("DATA 4 MX6_MMDC_P1_MPWRDLCTL\t= 0x%08X\n", 381 calib->p1_mpwrdlctl); 382 printf("DATA 4 MX6_MMDC_P1_MPWLDECTRL0\t= 0x%08X\n", 383 calib->p1_mpwldectrl0); 384 printf("DATA 4 MX6_MMDC_P1_MPWLDECTRL1\t= 0x%08X\n", 385 calib->p1_mpwldectrl1); 386 } 387 #endif 388 } 389 390 /* 391 * called from C runtime startup code (arch/arm/lib/crt0.S:_main) 392 * - we have a stack and a place to store GD, both in SRAM 393 * - no variable global data is available 394 */ 395 void board_init_f(ulong dummy) 396 { 397 int errs; 398 struct mx6_mmdc_calibration calibration = {0}; 399 400 memset((void *)gd, 0, sizeof(struct global_data)); 401 402 /* write leveling calibration defaults */ 403 calibration.p0_mpwrdlctl = 0x40404040; 404 calibration.p1_mpwrdlctl = 0x40404040; 405 406 /* setup AIPS and disable watchdog */ 407 arch_cpu_init(); 408 409 ccgr_init(); 410 411 SETUP_IOMUX_PADS(uart_pads); 412 413 /* setup GP timer */ 414 timer_init(); 415 416 /* UART clocks enabled and gd valid - init serial console */ 417 preloader_console_init(); 418 419 if (sysinfo.dsize != 1) { 420 if (is_cpu_type(MXC_CPU_MX6SX) || 421 is_cpu_type(MXC_CPU_MX6UL) || 422 is_cpu_type(MXC_CPU_MX6ULL) || 423 is_cpu_type(MXC_CPU_MX6SL)) { 424 printf("cpu type 0x%x doesn't support 64-bit bus\n", 425 get_cpu_type()); 426 reset_cpu(0); 427 } 428 } 429 #ifdef CONFIG_MX6SL 430 mx6sl_dram_iocfg(CONFIG_DDRWIDTH, &mx6sl_ddr_ioregs, 431 &mx6sl_grp_ioregs); 432 #else 433 if (is_cpu_type(MXC_CPU_MX6Q)) { 434 mx6dq_dram_iocfg(CONFIG_DDRWIDTH, &mx6dq_ddr_ioregs, 435 &mx6dq_grp_ioregs); 436 } else { 437 mx6sdl_dram_iocfg(CONFIG_DDRWIDTH, &mx6sdl_ddr_ioregs, 438 &mx6sdl_grp_ioregs); 439 } 440 #endif 441 mx6_dram_cfg(&sysinfo, &calibration, &ddrtype); 442 443 errs = mmdc_do_write_level_calibration(&sysinfo); 444 if (errs) { 445 printf("error %d from write level calibration\n", errs); 446 } else { 447 errs = mmdc_do_dqs_calibration(&sysinfo); 448 if (errs) { 449 printf("error %d from dqs calibration\n", errs); 450 } else { 451 printf("completed successfully\n"); 452 mmdc_read_calibration(&sysinfo, &calibration); 453 display_calibration(&calibration); 454 } 455 } 456 } 457