1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Nexell Co., Ltd. 4 * 5 * Author: junghyun, kim <jhkim@nexell.co.kr> 6 */ 7 8 #include <config.h> 9 #include <common.h> 10 #include <errno.h> 11 12 #include <asm/arch/nexell.h> 13 #include <asm/arch/tieoff.h> 14 #include <asm/arch/reset.h> 15 #include <asm/arch/display.h> 16 17 #include "soc/s5pxx18_soc_mipi.h" 18 #include "soc/s5pxx18_soc_disptop.h" 19 #include "soc/s5pxx18_soc_disptop_clk.h" 20 21 #define PLLPMS_1000MHZ 0x33E8 22 #define BANDCTL_1000MHZ 0xF 23 #define PLLPMS_960MHZ 0x2280 24 #define BANDCTL_960MHZ 0xF 25 #define PLLPMS_900MHZ 0x2258 26 #define BANDCTL_900MHZ 0xE 27 #define PLLPMS_840MHZ 0x2230 28 #define BANDCTL_840MHZ 0xD 29 #define PLLPMS_750MHZ 0x43E8 30 #define BANDCTL_750MHZ 0xC 31 #define PLLPMS_660MHZ 0x21B8 32 #define BANDCTL_660MHZ 0xB 33 #define PLLPMS_600MHZ 0x2190 34 #define BANDCTL_600MHZ 0xA 35 #define PLLPMS_540MHZ 0x2168 36 #define BANDCTL_540MHZ 0x9 37 #define PLLPMS_512MHZ 0x03200 38 #define BANDCTL_512MHZ 0x9 39 #define PLLPMS_480MHZ 0x2281 40 #define BANDCTL_480MHZ 0x8 41 #define PLLPMS_420MHZ 0x2231 42 #define BANDCTL_420MHZ 0x7 43 #define PLLPMS_402MHZ 0x2219 44 #define BANDCTL_402MHZ 0x7 45 #define PLLPMS_330MHZ 0x21B9 46 #define BANDCTL_330MHZ 0x6 47 #define PLLPMS_300MHZ 0x2191 48 #define BANDCTL_300MHZ 0x5 49 #define PLLPMS_210MHZ 0x2232 50 #define BANDCTL_210MHZ 0x4 51 #define PLLPMS_180MHZ 0x21E2 52 #define BANDCTL_180MHZ 0x3 53 #define PLLPMS_150MHZ 0x2192 54 #define BANDCTL_150MHZ 0x2 55 #define PLLPMS_100MHZ 0x3323 56 #define BANDCTL_100MHZ 0x1 57 #define PLLPMS_80MHZ 0x3283 58 #define BANDCTL_80MHZ 0x0 59 60 #define MIPI_INDEX 0 61 #define MIPI_EXC_PRE_VALUE 1 62 #define MIPI_DSI_IRQ_MASK 29 63 64 #define __io_address(a) (void *)(uintptr_t)(a) 65 66 struct mipi_xfer_msg { 67 u8 id, data[2]; 68 u16 flags; 69 const u8 *tx_buf; 70 u16 tx_len; 71 u8 *rx_buf; 72 u16 rx_len; 73 }; 74 75 static void mipi_reset(void) 76 { 77 /* tieoff */ 78 nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA, 3); 79 nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB, 3); 80 81 /* reset */ 82 nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_ASSERT); 83 nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_ASSERT); 84 nx_rstcon_setrst(RESET_ID_MIPI_CSI, RSTCON_ASSERT); 85 nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_ASSERT); 86 nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_ASSERT); 87 88 nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_NEGATE); 89 nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_NEGATE); 90 nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_NEGATE); 91 nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_NEGATE); 92 } 93 94 static void mipi_init(void) 95 { 96 int clkid = DP_CLOCK_MIPI; 97 void *base; 98 99 /* 100 * neet to reset before open 101 */ 102 mipi_reset(); 103 104 base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid)); 105 nx_disp_top_clkgen_set_base_address(clkid, base); 106 nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always); 107 108 base = __io_address(nx_mipi_get_physical_address(0)); 109 nx_mipi_set_base_address(0, base); 110 } 111 112 static int mipi_get_phy_pll(int bitrate, unsigned int *pllpms, 113 unsigned int *bandctl) 114 { 115 unsigned int pms, ctl; 116 117 switch (bitrate) { 118 case 1000: 119 pms = PLLPMS_1000MHZ; 120 ctl = BANDCTL_1000MHZ; 121 break; 122 case 960: 123 pms = PLLPMS_960MHZ; 124 ctl = BANDCTL_960MHZ; 125 break; 126 case 900: 127 pms = PLLPMS_900MHZ; 128 ctl = BANDCTL_900MHZ; 129 break; 130 case 840: 131 pms = PLLPMS_840MHZ; 132 ctl = BANDCTL_840MHZ; 133 break; 134 case 750: 135 pms = PLLPMS_750MHZ; 136 ctl = BANDCTL_750MHZ; 137 break; 138 case 660: 139 pms = PLLPMS_660MHZ; 140 ctl = BANDCTL_660MHZ; 141 break; 142 case 600: 143 pms = PLLPMS_600MHZ; 144 ctl = BANDCTL_600MHZ; 145 break; 146 case 540: 147 pms = PLLPMS_540MHZ; 148 ctl = BANDCTL_540MHZ; 149 break; 150 case 512: 151 pms = PLLPMS_512MHZ; 152 ctl = BANDCTL_512MHZ; 153 break; 154 case 480: 155 pms = PLLPMS_480MHZ; 156 ctl = BANDCTL_480MHZ; 157 break; 158 case 420: 159 pms = PLLPMS_420MHZ; 160 ctl = BANDCTL_420MHZ; 161 break; 162 case 402: 163 pms = PLLPMS_402MHZ; 164 ctl = BANDCTL_402MHZ; 165 break; 166 case 330: 167 pms = PLLPMS_330MHZ; 168 ctl = BANDCTL_330MHZ; 169 break; 170 case 300: 171 pms = PLLPMS_300MHZ; 172 ctl = BANDCTL_300MHZ; 173 break; 174 case 210: 175 pms = PLLPMS_210MHZ; 176 ctl = BANDCTL_210MHZ; 177 break; 178 case 180: 179 pms = PLLPMS_180MHZ; 180 ctl = BANDCTL_180MHZ; 181 break; 182 case 150: 183 pms = PLLPMS_150MHZ; 184 ctl = BANDCTL_150MHZ; 185 break; 186 case 100: 187 pms = PLLPMS_100MHZ; 188 ctl = BANDCTL_100MHZ; 189 break; 190 case 80: 191 pms = PLLPMS_80MHZ; 192 ctl = BANDCTL_80MHZ; 193 break; 194 default: 195 return -EINVAL; 196 } 197 198 *pllpms = pms; 199 *bandctl = ctl; 200 201 return 0; 202 } 203 204 static int mipi_prepare(int module, int input, 205 struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, 206 struct dp_mipi_dev *mipi) 207 { 208 int index = MIPI_INDEX; 209 u32 esc_pre_value = MIPI_EXC_PRE_VALUE; 210 int lpm = mipi->lpm_trans; 211 int ret = 0; 212 213 ret = mipi_get_phy_pll(mipi->hs_bitrate, 214 &mipi->hs_pllpms, &mipi->hs_bandctl); 215 if (ret < 0) 216 return ret; 217 218 ret = mipi_get_phy_pll(mipi->lp_bitrate, 219 &mipi->lp_pllpms, &mipi->lp_bandctl); 220 if (ret < 0) 221 return ret; 222 223 debug("%s: mipi lp:%dmhz:0x%x:0x%x, hs:%dmhz:0x%x:0x%x, %s trans\n", 224 __func__, mipi->lp_bitrate, mipi->lp_pllpms, mipi->lp_bandctl, 225 mipi->hs_bitrate, mipi->hs_pllpms, mipi->hs_bandctl, 226 lpm ? "low" : "high"); 227 228 if (lpm) 229 nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, 230 mipi->lp_pllpms, mipi->lp_bandctl, 0, 0); 231 else 232 nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, 233 mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); 234 235 #ifdef CONFIG_ARCH_S5P4418 236 /* 237 * disable the escape clock generating prescaler 238 * before soft reset. 239 */ 240 nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 0, 10); 241 mdelay(1); 242 #endif 243 244 nx_mipi_dsi_software_reset(index); 245 nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 1, esc_pre_value); 246 nx_mipi_dsi_set_phy(index, 0, 1, 1, 0, 0, 0, 0, 0); 247 248 if (lpm) 249 nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_lp, 250 nx_mipi_dsi_lpmode_lp); 251 else 252 nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_hs, 253 nx_mipi_dsi_lpmode_hs); 254 mdelay(20); 255 256 return 0; 257 } 258 259 static int mipi_enable(int module, int input, 260 struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, 261 struct dp_mipi_dev *mipi) 262 { 263 struct mipi_dsi_device *dsi = &mipi->dsi; 264 int clkid = DP_CLOCK_MIPI; 265 int index = MIPI_INDEX; 266 int width = sync->h_active_len; 267 int height = sync->v_active_len; 268 int HFP = sync->h_front_porch; 269 int HBP = sync->h_back_porch; 270 int HS = sync->h_sync_width; 271 int VFP = sync->v_front_porch; 272 int VBP = sync->v_back_porch; 273 int VS = sync->v_sync_width; 274 int en_prescaler = 1; 275 u32 esc_pre_value = MIPI_EXC_PRE_VALUE; 276 277 int txhsclock = 1; 278 int lpm = mipi->lpm_trans; 279 bool command_mode = mipi->command_mode; 280 281 enum nx_mipi_dsi_format dsi_format; 282 int data_len = dsi->lanes - 1; 283 bool burst = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? true : false; 284 bool eot_enable = dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ? 285 false : true; 286 287 /* 288 * disable the escape clock generating prescaler 289 * before soft reset. 290 */ 291 #ifdef CONFIG_ARCH_S5P4418 292 en_prescaler = 0; 293 #endif 294 295 debug("%s: mode:%s, lanes.%d\n", __func__, 296 command_mode ? "command" : "video", data_len + 1); 297 298 if (lpm) 299 nx_mipi_dsi_set_escape_lp(index, 300 nx_mipi_dsi_lpmode_hs, 301 nx_mipi_dsi_lpmode_hs); 302 303 nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, 304 mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); 305 mdelay(1); 306 307 nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, en_prescaler, 10); 308 mdelay(1); 309 310 nx_mipi_dsi_software_reset(index); 311 nx_mipi_dsi_set_clock(index, txhsclock, 0, 1, 312 1, 1, 0, 0, 0, 1, esc_pre_value); 313 314 switch (data_len) { 315 case 0: /* 1 lane */ 316 nx_mipi_dsi_set_phy(index, data_len, 1, 1, 0, 0, 0, 0, 0); 317 break; 318 case 1: /* 2 lane */ 319 nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 0, 0, 0, 0); 320 break; 321 case 2: /* 3 lane */ 322 nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 0, 0, 0); 323 break; 324 case 3: /* 3 lane */ 325 nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 1, 0, 0); 326 break; 327 default: 328 printf("%s: not support data lanes %d\n", 329 __func__, data_len + 1); 330 return -EINVAL; 331 } 332 333 switch (dsi->format) { 334 case MIPI_DSI_FMT_RGB565: 335 dsi_format = nx_mipi_dsi_format_rgb565; 336 break; 337 case MIPI_DSI_FMT_RGB666: 338 dsi_format = nx_mipi_dsi_format_rgb666; 339 break; 340 case MIPI_DSI_FMT_RGB666_PACKED: 341 dsi_format = nx_mipi_dsi_format_rgb666_packed; 342 break; 343 case MIPI_DSI_FMT_RGB888: 344 dsi_format = nx_mipi_dsi_format_rgb888; 345 break; 346 default: 347 printf("%s: not support format %d\n", __func__, dsi->format); 348 return -EINVAL; 349 } 350 351 nx_mipi_dsi_set_config_video_mode(index, 1, 0, burst, 352 nx_mipi_dsi_syncmode_event, 353 eot_enable, 1, 1, 1, 1, 0, dsi_format, 354 HFP, HBP, HS, VFP, VBP, VS, 0); 355 356 nx_mipi_dsi_set_size(index, width, height); 357 358 /* set mux */ 359 nx_disp_top_set_mipimux(1, module); 360 361 /* 0 is spdif, 1 is mipi vclk */ 362 nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv0); 363 nx_disp_top_clkgen_set_clock_divisor(clkid, 1, 364 ctrl->clk_div_lv1 * 365 ctrl->clk_div_lv0); 366 367 /* SPDIF and MIPI */ 368 nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 1); 369 370 /* START: CLKGEN, MIPI is started in setup function */ 371 nx_disp_top_clkgen_set_clock_divisor_enable(clkid, true); 372 nx_mipi_dsi_set_enable(index, true); 373 374 return 0; 375 } 376 377 static int nx_mipi_transfer_tx(struct mipi_dsi_device *dsi, 378 struct mipi_xfer_msg *xfer) 379 { 380 const u8 *txb; 381 int size, index = 0; 382 u32 data; 383 384 if (xfer->tx_len > DSI_TX_FIFO_SIZE) 385 printf("warn: tx %d size over fifo %d\n", 386 (int)xfer->tx_len, DSI_TX_FIFO_SIZE); 387 388 /* write payload */ 389 size = xfer->tx_len; 390 txb = xfer->tx_buf; 391 392 while (size >= 4) { 393 data = (txb[3] << 24) | (txb[2] << 16) | 394 (txb[1] << 8) | (txb[0]); 395 nx_mipi_dsi_write_payload(index, data); 396 txb += 4, size -= 4; 397 data = 0; 398 } 399 400 switch (size) { 401 case 3: 402 data |= txb[2] << 16; 403 case 2: 404 data |= txb[1] << 8; 405 case 1: 406 data |= txb[0]; 407 nx_mipi_dsi_write_payload(index, data); 408 break; 409 case 0: 410 break; /* no payload */ 411 } 412 413 /* write packet hdr */ 414 data = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->id; 415 416 nx_mipi_dsi_write_pkheader(index, data); 417 418 return 0; 419 } 420 421 static int nx_mipi_transfer_done(struct mipi_dsi_device *dsi) 422 { 423 int index = 0, count = 100; 424 u32 value; 425 426 do { 427 mdelay(1); 428 value = nx_mipi_dsi_read_fifo_status(index); 429 if (((1 << 22) & value)) 430 break; 431 } while (count-- > 0); 432 433 if (count < 0) 434 return -EINVAL; 435 436 return 0; 437 } 438 439 static int nx_mipi_transfer_rx(struct mipi_dsi_device *dsi, 440 struct mipi_xfer_msg *xfer) 441 { 442 u8 *rxb = xfer->rx_buf; 443 int index = 0, rx_len = 0; 444 u32 data, count = 0; 445 u16 size; 446 int err = -EINVAL; 447 448 nx_mipi_dsi_clear_interrupt_pending(index, 18); 449 450 while (1) { 451 /* Completes receiving data. */ 452 if (nx_mipi_dsi_get_interrupt_pending(index, 18)) 453 break; 454 455 mdelay(1); 456 457 if (count > 500) { 458 printf("%s: error recevice data\n", __func__); 459 err = -EINVAL; 460 goto clear_fifo; 461 } else { 462 count++; 463 } 464 } 465 466 data = nx_mipi_dsi_read_fifo(index); 467 468 switch (data & 0x3f) { 469 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: 470 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: 471 if (xfer->rx_len >= 2) { 472 rxb[1] = data >> 16; 473 rx_len++; 474 } 475 476 /* Fall through */ 477 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: 478 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: 479 rxb[0] = data >> 8; 480 rx_len++; 481 xfer->rx_len = rx_len; 482 err = rx_len; 483 goto clear_fifo; 484 485 case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: 486 printf("DSI Error Report: 0x%04x\n", (data >> 8) & 0xffff); 487 err = rx_len; 488 goto clear_fifo; 489 } 490 491 size = (data >> 8) & 0xffff; 492 493 if (size > xfer->rx_len) 494 size = xfer->rx_len; 495 else if (size < xfer->rx_len) 496 xfer->rx_len = size; 497 498 size = xfer->rx_len - rx_len; 499 rx_len += size; 500 501 /* Receive payload */ 502 while (size >= 4) { 503 data = nx_mipi_dsi_read_fifo(index); 504 rxb[0] = (data >> 0) & 0xff; 505 rxb[1] = (data >> 8) & 0xff; 506 rxb[2] = (data >> 16) & 0xff; 507 rxb[3] = (data >> 24) & 0xff; 508 rxb += 4, size -= 4; 509 } 510 511 if (size) { 512 data = nx_mipi_dsi_read_fifo(index); 513 switch (size) { 514 case 3: 515 rxb[2] = (data >> 16) & 0xff; 516 case 2: 517 rxb[1] = (data >> 8) & 0xff; 518 case 1: 519 rxb[0] = data & 0xff; 520 } 521 } 522 523 if (rx_len == xfer->rx_len) 524 err = rx_len; 525 526 clear_fifo: 527 size = DSI_RX_FIFO_SIZE / 4; 528 do { 529 data = nx_mipi_dsi_read_fifo(index); 530 if (data == DSI_RX_FIFO_EMPTY) 531 break; 532 } while (--size); 533 534 return err; 535 } 536 537 #define IS_SHORT(t) (9 > ((t) & 0x0f)) 538 539 static int nx_mipi_transfer(struct mipi_dsi_device *dsi, 540 const struct mipi_dsi_msg *msg) 541 { 542 struct mipi_xfer_msg xfer; 543 int err; 544 545 if (!msg->tx_len) 546 return -EINVAL; 547 548 /* set id */ 549 xfer.id = msg->type | (msg->channel << 6); 550 551 /* short type msg */ 552 if (IS_SHORT(msg->type)) { 553 const char *txb = msg->tx_buf; 554 555 if (msg->tx_len > 2) 556 return -EINVAL; 557 558 xfer.tx_len = 0; /* no payload */ 559 xfer.data[0] = txb[0]; 560 xfer.data[1] = (msg->tx_len == 2) ? txb[1] : 0; 561 xfer.tx_buf = NULL; 562 } else { 563 xfer.tx_len = msg->tx_len; 564 xfer.data[0] = msg->tx_len & 0xff; 565 xfer.data[1] = msg->tx_len >> 8; 566 xfer.tx_buf = msg->tx_buf; 567 } 568 569 xfer.rx_len = msg->rx_len; 570 xfer.rx_buf = msg->rx_buf; 571 xfer.flags = msg->flags; 572 573 err = nx_mipi_transfer_tx(dsi, &xfer); 574 575 if (xfer.rx_len) 576 err = nx_mipi_transfer_rx(dsi, &xfer); 577 578 nx_mipi_transfer_done(dsi); 579 580 return err; 581 } 582 583 static ssize_t nx_mipi_write_buffer(struct mipi_dsi_device *dsi, 584 const void *data, size_t len) 585 { 586 struct mipi_dsi_msg msg = { 587 .channel = dsi->channel, 588 .tx_buf = data, 589 .tx_len = len 590 }; 591 592 switch (len) { 593 case 0: 594 return -EINVAL; 595 case 1: 596 msg.type = MIPI_DSI_DCS_SHORT_WRITE; 597 break; 598 case 2: 599 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; 600 break; 601 default: 602 msg.type = MIPI_DSI_DCS_LONG_WRITE; 603 break; 604 } 605 606 if (dsi->mode_flags & MIPI_DSI_MODE_LPM) 607 msg.flags |= MIPI_DSI_MSG_USE_LPM; 608 609 return nx_mipi_transfer(dsi, &msg); 610 } 611 612 __weak int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi) 613 { 614 return 0; 615 } 616 617 /* 618 * disply 619 * MIPI DSI Setting 620 * (1) Initiallize MIPI(DSIM,DPHY,PLL) 621 * (2) Initiallize LCD 622 * (3) ReInitiallize MIPI(DSIM only) 623 * (4) Turn on display(MLC,DPC,...) 624 */ 625 void nx_mipi_display(int module, 626 struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, 627 struct dp_plane_top *top, struct dp_plane_info *planes, 628 struct dp_mipi_dev *dev) 629 { 630 struct dp_plane_info *plane = planes; 631 struct mipi_dsi_device *dsi = &dev->dsi; 632 int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; 633 int count = top->plane_num; 634 int i = 0, ret; 635 636 printf("MIPI: dp.%d\n", module); 637 638 /* map mipi-dsi write callback func */ 639 dsi->write_buffer = nx_mipi_write_buffer; 640 641 ret = nx_mipi_dsi_lcd_bind(dsi); 642 if (ret) { 643 printf("Error: bind mipi-dsi lcd driver !\n"); 644 return; 645 } 646 647 dp_control_init(module); 648 dp_plane_init(module); 649 650 mipi_init(); 651 652 /* set plane */ 653 dp_plane_screen_setup(module, top); 654 655 for (i = 0; count > i; i++, plane++) { 656 if (!plane->enable) 657 continue; 658 dp_plane_layer_setup(module, plane); 659 dp_plane_layer_enable(module, plane, 1); 660 } 661 dp_plane_screen_enable(module, 1); 662 663 /* set mipi */ 664 mipi_prepare(module, input, sync, ctrl, dev); 665 666 if (dsi->ops && dsi->ops->prepare) 667 dsi->ops->prepare(dsi); 668 669 if (dsi->ops && dsi->ops->enable) 670 dsi->ops->enable(dsi); 671 672 mipi_enable(module, input, sync, ctrl, dev); 673 674 /* set dp control */ 675 dp_control_setup(module, sync, ctrl); 676 dp_control_enable(module, 1); 677 } 678