broadsheetfb.c (28621B)
1/* 2 * broadsheetfb.c -- FB driver for E-Ink Broadsheet controller 3 * 4 * Copyright (C) 2008, Jaya Kumar 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file COPYING in the main directory of this archive for 8 * more details. 9 * 10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. 11 * 12 * This driver is written to be used with the Broadsheet display controller. 13 * 14 * It is intended to be architecture independent. A board specific driver 15 * must be used to perform all the physical IO interactions. 16 * 17 */ 18 19#include <linux/module.h> 20#include <linux/kernel.h> 21#include <linux/errno.h> 22#include <linux/string.h> 23#include <linux/mm.h> 24#include <linux/slab.h> 25#include <linux/vmalloc.h> 26#include <linux/delay.h> 27#include <linux/interrupt.h> 28#include <linux/fb.h> 29#include <linux/init.h> 30#include <linux/platform_device.h> 31#include <linux/list.h> 32#include <linux/firmware.h> 33#include <linux/uaccess.h> 34 35#include <video/broadsheetfb.h> 36 37/* track panel specific parameters */ 38struct panel_info { 39 int w; 40 int h; 41 u16 sdcfg; 42 u16 gdcfg; 43 u16 lutfmt; 44 u16 fsynclen; 45 u16 fendfbegin; 46 u16 lsynclen; 47 u16 lendlbegin; 48 u16 pixclk; 49}; 50 51/* table of panel specific parameters to be indexed into by the board drivers */ 52static struct panel_info panel_table[] = { 53 { /* standard 6" on TFT backplane */ 54 .w = 800, 55 .h = 600, 56 .sdcfg = (100 | (1 << 8) | (1 << 9)), 57 .gdcfg = 2, 58 .lutfmt = (4 | (1 << 7)), 59 .fsynclen = 4, 60 .fendfbegin = (10 << 8) | 4, 61 .lsynclen = 10, 62 .lendlbegin = (100 << 8) | 4, 63 .pixclk = 6, 64 }, 65 { /* custom 3.7" flexible on PET or steel */ 66 .w = 320, 67 .h = 240, 68 .sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)), 69 .gdcfg = 3, 70 .lutfmt = (4 | (1 << 7)), 71 .fsynclen = 0, 72 .fendfbegin = (80 << 8) | 4, 73 .lsynclen = 10, 74 .lendlbegin = (80 << 8) | 20, 75 .pixclk = 14, 76 }, 77 { /* standard 9.7" on TFT backplane */ 78 .w = 1200, 79 .h = 825, 80 .sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)), 81 .gdcfg = 2, 82 .lutfmt = (4 | (1 << 7)), 83 .fsynclen = 0, 84 .fendfbegin = (4 << 8) | 4, 85 .lsynclen = 4, 86 .lendlbegin = (60 << 8) | 10, 87 .pixclk = 3, 88 }, 89}; 90 91#define DPY_W 800 92#define DPY_H 600 93 94static struct fb_fix_screeninfo broadsheetfb_fix = { 95 .id = "broadsheetfb", 96 .type = FB_TYPE_PACKED_PIXELS, 97 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, 98 .xpanstep = 0, 99 .ypanstep = 0, 100 .ywrapstep = 0, 101 .line_length = DPY_W, 102 .accel = FB_ACCEL_NONE, 103}; 104 105static struct fb_var_screeninfo broadsheetfb_var = { 106 .xres = DPY_W, 107 .yres = DPY_H, 108 .xres_virtual = DPY_W, 109 .yres_virtual = DPY_H, 110 .bits_per_pixel = 8, 111 .grayscale = 1, 112 .red = { 0, 4, 0 }, 113 .green = { 0, 4, 0 }, 114 .blue = { 0, 4, 0 }, 115 .transp = { 0, 0, 0 }, 116}; 117 118/* main broadsheetfb functions */ 119static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data) 120{ 121 par->board->set_ctl(par, BS_WR, 0); 122 par->board->set_hdb(par, data); 123 par->board->set_ctl(par, BS_WR, 1); 124} 125 126static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data) 127{ 128 par->board->set_ctl(par, BS_DC, 0); 129 broadsheet_gpio_issue_data(par, data); 130} 131 132static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data) 133{ 134 par->board->wait_for_rdy(par); 135 136 par->board->set_ctl(par, BS_CS, 0); 137 broadsheet_gpio_issue_cmd(par, data); 138 par->board->set_ctl(par, BS_DC, 1); 139 par->board->set_ctl(par, BS_CS, 1); 140} 141 142static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd, 143 int argc, u16 *argv) 144{ 145 int i; 146 147 par->board->wait_for_rdy(par); 148 149 par->board->set_ctl(par, BS_CS, 0); 150 broadsheet_gpio_issue_cmd(par, cmd); 151 par->board->set_ctl(par, BS_DC, 1); 152 153 for (i = 0; i < argc; i++) 154 broadsheet_gpio_issue_data(par, argv[i]); 155 par->board->set_ctl(par, BS_CS, 1); 156} 157 158static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd, 159 int argc, u16 *argv) 160{ 161 int i; 162 163 par->board->mmio_write(par, BS_MMIO_CMD, cmd); 164 165 for (i = 0; i < argc; i++) 166 par->board->mmio_write(par, BS_MMIO_DATA, argv[i]); 167} 168 169static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data) 170{ 171 if (par->board->mmio_write) 172 par->board->mmio_write(par, BS_MMIO_CMD, data); 173 else 174 broadsheet_gpio_send_command(par, data); 175} 176 177static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd, 178 int argc, u16 *argv) 179{ 180 if (par->board->mmio_write) 181 broadsheet_mmio_send_cmdargs(par, cmd, argc, argv); 182 else 183 broadsheet_gpio_send_cmdargs(par, cmd, argc, argv); 184} 185 186static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size, 187 u16 *data) 188{ 189 int i; 190 u16 tmp; 191 192 par->board->set_ctl(par, BS_CS, 0); 193 par->board->set_ctl(par, BS_DC, 1); 194 195 for (i = 0; i < size; i++) { 196 par->board->set_ctl(par, BS_WR, 0); 197 tmp = (data[i] & 0x0F) << 4; 198 tmp |= (data[i] & 0x0F00) << 4; 199 par->board->set_hdb(par, tmp); 200 par->board->set_ctl(par, BS_WR, 1); 201 } 202 203 par->board->set_ctl(par, BS_CS, 1); 204} 205 206static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size, 207 u16 *data) 208{ 209 int i; 210 u16 tmp; 211 212 for (i = 0; i < size; i++) { 213 tmp = (data[i] & 0x0F) << 4; 214 tmp |= (data[i] & 0x0F00) << 4; 215 par->board->mmio_write(par, BS_MMIO_DATA, tmp); 216 } 217 218} 219 220static void broadsheet_burst_write(struct broadsheetfb_par *par, int size, 221 u16 *data) 222{ 223 if (par->board->mmio_write) 224 broadsheet_mmio_burst_write(par, size, data); 225 else 226 broadsheet_gpio_burst_write(par, size, data); 227} 228 229static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par) 230{ 231 u16 res; 232 /* wait for ready to go hi. (lo is busy) */ 233 par->board->wait_for_rdy(par); 234 235 /* cs lo, dc lo for cmd, we lo for each data, db as usual */ 236 par->board->set_ctl(par, BS_DC, 1); 237 par->board->set_ctl(par, BS_CS, 0); 238 par->board->set_ctl(par, BS_WR, 0); 239 240 res = par->board->get_hdb(par); 241 242 /* strobe wr */ 243 par->board->set_ctl(par, BS_WR, 1); 244 par->board->set_ctl(par, BS_CS, 1); 245 246 return res; 247} 248 249 250static u16 broadsheet_get_data(struct broadsheetfb_par *par) 251{ 252 if (par->board->mmio_read) 253 return par->board->mmio_read(par); 254 else 255 return broadsheet_gpio_get_data(par); 256} 257 258static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg, 259 u16 data) 260{ 261 /* wait for ready to go hi. (lo is busy) */ 262 par->board->wait_for_rdy(par); 263 264 /* cs lo, dc lo for cmd, we lo for each data, db as usual */ 265 par->board->set_ctl(par, BS_CS, 0); 266 267 broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG); 268 269 par->board->set_ctl(par, BS_DC, 1); 270 271 broadsheet_gpio_issue_data(par, reg); 272 broadsheet_gpio_issue_data(par, data); 273 274 par->board->set_ctl(par, BS_CS, 1); 275} 276 277static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg, 278 u16 data) 279{ 280 par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG); 281 par->board->mmio_write(par, BS_MMIO_DATA, reg); 282 par->board->mmio_write(par, BS_MMIO_DATA, data); 283 284} 285 286static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg, 287 u16 data) 288{ 289 if (par->board->mmio_write) 290 broadsheet_mmio_write_reg(par, reg, data); 291 else 292 broadsheet_gpio_write_reg(par, reg, data); 293} 294 295static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg, 296 u32 data) 297{ 298 broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF); 299 broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF); 300} 301 302 303static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg) 304{ 305 broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, ®); 306 par->board->wait_for_rdy(par); 307 return broadsheet_get_data(par); 308} 309 310/* functions for waveform manipulation */ 311static int is_broadsheet_pll_locked(struct broadsheetfb_par *par) 312{ 313 return broadsheet_read_reg(par, 0x000A) & 0x0001; 314} 315 316static int broadsheet_setup_plls(struct broadsheetfb_par *par) 317{ 318 int retry_count = 0; 319 u16 tmp; 320 321 /* disable arral saemipu mode */ 322 broadsheet_write_reg(par, 0x0006, 0x0000); 323 324 broadsheet_write_reg(par, 0x0010, 0x0004); 325 broadsheet_write_reg(par, 0x0012, 0x5949); 326 broadsheet_write_reg(par, 0x0014, 0x0040); 327 broadsheet_write_reg(par, 0x0016, 0x0000); 328 329 do { 330 if (retry_count++ > 100) 331 return -ETIMEDOUT; 332 mdelay(1); 333 } while (!is_broadsheet_pll_locked(par)); 334 335 tmp = broadsheet_read_reg(par, 0x0006); 336 tmp &= ~0x1; 337 broadsheet_write_reg(par, 0x0006, tmp); 338 339 return 0; 340} 341 342static int broadsheet_setup_spi(struct broadsheetfb_par *par) 343{ 344 345 broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1)); 346 broadsheet_write_reg(par, 0x0208, 0x0001); 347 348 return 0; 349} 350 351static int broadsheet_setup_spiflash(struct broadsheetfb_par *par, 352 u16 *orig_sfmcd) 353{ 354 355 *orig_sfmcd = broadsheet_read_reg(par, 0x0204); 356 broadsheet_write_reg(par, 0x0208, 0); 357 broadsheet_write_reg(par, 0x0204, 0); 358 broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1)); 359 360 return 0; 361} 362 363static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par, 364 u16 reg, int bitnum, int val, 365 int timeout) 366{ 367 u16 tmp; 368 369 do { 370 tmp = broadsheet_read_reg(par, reg); 371 if (((tmp >> bitnum) & 1) == val) 372 return 0; 373 mdelay(1); 374 } while (timeout--); 375 376 return -ETIMEDOUT; 377} 378 379static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data) 380{ 381 broadsheet_write_reg(par, 0x0202, (data | 0x100)); 382 383 return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100); 384} 385 386static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data) 387{ 388 int err; 389 u16 tmp; 390 391 broadsheet_write_reg(par, 0x0202, 0); 392 393 err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100); 394 if (err) 395 return err; 396 397 tmp = broadsheet_read_reg(par, 0x200); 398 399 *data = tmp & 0xFF; 400 401 return 0; 402} 403 404static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par, 405 int timeout) 406{ 407 u8 tmp; 408 int err; 409 410 do { 411 broadsheet_write_reg(par, 0x0208, 1); 412 413 err = broadsheet_spiflash_write_byte(par, 0x05); 414 if (err) 415 goto failout; 416 417 err = broadsheet_spiflash_read_byte(par, &tmp); 418 if (err) 419 goto failout; 420 421 broadsheet_write_reg(par, 0x0208, 0); 422 423 if (!(tmp & 0x1)) 424 return 0; 425 426 mdelay(5); 427 } while (timeout--); 428 429 dev_err(par->info->device, "Timed out waiting for spiflash status\n"); 430 return -ETIMEDOUT; 431 432failout: 433 broadsheet_write_reg(par, 0x0208, 0); 434 return err; 435} 436 437static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par, 438 u8 op, u32 addr) 439{ 440 int i; 441 u8 tmp; 442 int err; 443 444 broadsheet_write_reg(par, 0x0208, 1); 445 446 err = broadsheet_spiflash_write_byte(par, op); 447 if (err) 448 return err; 449 450 for (i = 2; i >= 0; i--) { 451 tmp = ((addr >> (i * 8)) & 0xFF); 452 err = broadsheet_spiflash_write_byte(par, tmp); 453 if (err) 454 return err; 455 } 456 457 return err; 458} 459 460static int broadsheet_verify_spiflash(struct broadsheetfb_par *par, 461 int *flash_type) 462{ 463 int err = 0; 464 u8 sig; 465 466 err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000); 467 if (err) 468 goto failout; 469 470 err = broadsheet_spiflash_read_byte(par, &sig); 471 if (err) 472 goto failout; 473 474 if ((sig != 0x10) && (sig != 0x11)) { 475 dev_err(par->info->device, "Unexpected flash type\n"); 476 err = -EINVAL; 477 goto failout; 478 } 479 480 *flash_type = sig; 481 482failout: 483 broadsheet_write_reg(par, 0x0208, 0); 484 return err; 485} 486 487static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par, 488 u16 *initial_sfmcd, int *flash_type) 489 490{ 491 int err; 492 493 err = broadsheet_setup_plls(par); 494 if (err) 495 return err; 496 497 broadsheet_write_reg(par, 0x0106, 0x0203); 498 499 err = broadsheet_setup_spi(par); 500 if (err) 501 return err; 502 503 err = broadsheet_setup_spiflash(par, initial_sfmcd); 504 if (err) 505 return err; 506 507 return broadsheet_verify_spiflash(par, flash_type); 508} 509 510static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par, 511 int mode) 512{ 513 int err; 514 515 broadsheet_write_reg(par, 0x0208, 1); 516 if (mode) 517 err = broadsheet_spiflash_write_byte(par, 0x06); 518 else 519 err = broadsheet_spiflash_write_byte(par, 0x04); 520 521 broadsheet_write_reg(par, 0x0208, 0); 522 return err; 523} 524 525static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par, 526 int addr) 527{ 528 int err; 529 530 broadsheet_spiflash_write_control(par, 1); 531 532 err = broadsheet_spiflash_op_on_address(par, 0xD8, addr); 533 534 broadsheet_write_reg(par, 0x0208, 0); 535 536 if (err) 537 return err; 538 539 err = broadsheet_spiflash_wait_for_status(par, 1000); 540 541 return err; 542} 543 544static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par, 545 int addr, int size, char *data) 546{ 547 int err; 548 int i; 549 550 err = broadsheet_spiflash_op_on_address(par, 0x03, addr); 551 if (err) 552 goto failout; 553 554 for (i = 0; i < size; i++) { 555 err = broadsheet_spiflash_read_byte(par, &data[i]); 556 if (err) 557 goto failout; 558 } 559 560failout: 561 broadsheet_write_reg(par, 0x0208, 0); 562 return err; 563} 564 565#define BS_SPIFLASH_PAGE_SIZE 256 566static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par, 567 int addr, const char *data) 568{ 569 int err; 570 int i; 571 572 broadsheet_spiflash_write_control(par, 1); 573 574 err = broadsheet_spiflash_op_on_address(par, 0x02, addr); 575 if (err) 576 goto failout; 577 578 for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) { 579 err = broadsheet_spiflash_write_byte(par, data[i]); 580 if (err) 581 goto failout; 582 } 583 584 broadsheet_write_reg(par, 0x0208, 0); 585 586 err = broadsheet_spiflash_wait_for_status(par, 100); 587 588failout: 589 return err; 590} 591 592static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par, 593 int addr, const char *data, int sector_size) 594{ 595 int i; 596 int err; 597 598 for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) { 599 err = broadsheet_spiflash_write_page(par, addr + i, &data[i]); 600 if (err) 601 return err; 602 } 603 return 0; 604} 605 606/* 607 * The caller must guarantee that the data to be rewritten is entirely 608 * contained within this sector. That is, data_start_addr + data_len 609 * must be less than sector_start_addr + sector_size. 610 */ 611static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par, 612 int sector_size, int data_start_addr, 613 int data_len, const char *data) 614{ 615 int err; 616 char *sector_buffer; 617 int tail_start_addr; 618 int start_sector_addr; 619 620 sector_buffer = kzalloc(sector_size, GFP_KERNEL); 621 if (!sector_buffer) 622 return -ENOMEM; 623 624 /* the start address of the sector is the 0th byte of that sector */ 625 start_sector_addr = (data_start_addr / sector_size) * sector_size; 626 627 /* 628 * check if there is head data that we need to readback into our sector 629 * buffer first 630 */ 631 if (data_start_addr != start_sector_addr) { 632 /* 633 * we need to read every byte up till the start address of our 634 * data and we put it into our sector buffer. 635 */ 636 err = broadsheet_spiflash_read_range(par, start_sector_addr, 637 data_start_addr, sector_buffer); 638 if (err) 639 goto out; 640 } 641 642 /* now we copy our data into the right place in the sector buffer */ 643 memcpy(sector_buffer + data_start_addr, data, data_len); 644 645 /* 646 * now we check if there is a tail section of the sector that we need to 647 * readback. 648 */ 649 tail_start_addr = (data_start_addr + data_len) % sector_size; 650 651 if (tail_start_addr) { 652 int tail_len; 653 654 tail_len = sector_size - tail_start_addr; 655 656 /* now we read this tail into our sector buffer */ 657 err = broadsheet_spiflash_read_range(par, tail_start_addr, 658 tail_len, sector_buffer + tail_start_addr); 659 if (err) 660 goto out; 661 } 662 663 /* if we got here we have the full sector that we want to rewrite. */ 664 665 /* first erase the sector */ 666 err = broadsheet_spiflash_erase_sector(par, start_sector_addr); 667 if (err) 668 goto out; 669 670 /* now write it */ 671 err = broadsheet_spiflash_write_sector(par, start_sector_addr, 672 sector_buffer, sector_size); 673out: 674 kfree(sector_buffer); 675 return err; 676} 677 678static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr, 679 const u8 *wfm, int bytecount, int flash_type) 680{ 681 int sector_size; 682 int err; 683 int cur_addr; 684 int writecount; 685 int maxlen; 686 int offset = 0; 687 688 switch (flash_type) { 689 case 0x10: 690 sector_size = 32*1024; 691 break; 692 case 0x11: 693 default: 694 sector_size = 64*1024; 695 break; 696 } 697 698 while (bytecount) { 699 cur_addr = wfm_addr + offset; 700 maxlen = roundup(cur_addr, sector_size) - cur_addr; 701 writecount = min(bytecount, maxlen); 702 703 err = broadsheet_spiflash_rewrite_sector(par, sector_size, 704 cur_addr, writecount, wfm + offset); 705 if (err) 706 return err; 707 708 offset += writecount; 709 bytecount -= writecount; 710 } 711 712 return 0; 713} 714 715static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par, 716 const u8 *wfm, size_t wfm_size) 717{ 718 int err = 0; 719 u16 initial_sfmcd = 0; 720 int flash_type = 0; 721 722 err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type); 723 if (err) 724 goto failout; 725 726 err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type); 727 728failout: 729 broadsheet_write_reg(par, 0x0204, initial_sfmcd); 730 return err; 731} 732 733static ssize_t broadsheet_loadstore_waveform(struct device *dev, 734 struct device_attribute *attr, 735 const char *buf, size_t len) 736{ 737 int err; 738 struct fb_info *info = dev_get_drvdata(dev); 739 struct broadsheetfb_par *par = info->par; 740 const struct firmware *fw_entry; 741 742 if (len < 1) 743 return -EINVAL; 744 745 err = request_firmware(&fw_entry, "broadsheet.wbf", dev); 746 if (err < 0) { 747 dev_err(dev, "Failed to get broadsheet waveform\n"); 748 goto err_failed; 749 } 750 751 /* try to enforce reasonable min max on waveform */ 752 if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) { 753 dev_err(dev, "Invalid waveform\n"); 754 err = -EINVAL; 755 goto err_fw; 756 } 757 758 mutex_lock(&(par->io_lock)); 759 err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data, 760 fw_entry->size); 761 762 mutex_unlock(&(par->io_lock)); 763 if (err < 0) { 764 dev_err(dev, "Failed to store broadsheet waveform\n"); 765 goto err_fw; 766 } 767 768 dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size); 769 770 err = len; 771 772err_fw: 773 release_firmware(fw_entry); 774err_failed: 775 return err; 776} 777static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL, 778 broadsheet_loadstore_waveform); 779 780/* upper level functions that manipulate the display and other stuff */ 781static void broadsheet_init_display(struct broadsheetfb_par *par) 782{ 783 u16 args[5]; 784 int xres = par->info->var.xres; 785 int yres = par->info->var.yres; 786 787 args[0] = panel_table[par->panel_index].w; 788 args[1] = panel_table[par->panel_index].h; 789 args[2] = panel_table[par->panel_index].sdcfg; 790 args[3] = panel_table[par->panel_index].gdcfg; 791 args[4] = panel_table[par->panel_index].lutfmt; 792 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args); 793 794 /* did the controller really set it? */ 795 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args); 796 797 args[0] = panel_table[par->panel_index].fsynclen; 798 args[1] = panel_table[par->panel_index].fendfbegin; 799 args[2] = panel_table[par->panel_index].lsynclen; 800 args[3] = panel_table[par->panel_index].lendlbegin; 801 args[4] = panel_table[par->panel_index].pixclk; 802 broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args); 803 804 broadsheet_write_reg32(par, 0x310, xres*yres*2); 805 806 /* setup waveform */ 807 args[0] = 0x886; 808 args[1] = 0; 809 broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args); 810 811 broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR); 812 813 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 814 815 broadsheet_write_reg(par, 0x330, 0x84); 816 817 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 818 819 args[0] = (0x3 << 4); 820 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); 821 822 args[0] = 0x154; 823 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 824 825 broadsheet_burst_write(par, (panel_table[par->panel_index].w * 826 panel_table[par->panel_index].h)/2, 827 (u16 *) par->info->screen_base); 828 829 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 830 831 args[0] = 0x4300; 832 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 833 834 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 835 836 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 837 838 par->board->wait_for_rdy(par); 839} 840 841static void broadsheet_identify(struct broadsheetfb_par *par) 842{ 843 u16 rev, prc; 844 struct device *dev = par->info->device; 845 846 rev = broadsheet_read_reg(par, BS_REG_REV); 847 prc = broadsheet_read_reg(par, BS_REG_PRC); 848 dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc); 849 850 if (prc != 0x0047) 851 dev_warn(dev, "Unrecognized Broadsheet Product Code\n"); 852 if (rev != 0x0100) 853 dev_warn(dev, "Unrecognized Broadsheet Revision\n"); 854} 855 856static void broadsheet_init(struct broadsheetfb_par *par) 857{ 858 broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN); 859 /* the controller needs a second */ 860 msleep(1000); 861 broadsheet_init_display(par); 862} 863 864static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par, 865 u16 y1, u16 y2) 866{ 867 u16 args[5]; 868 unsigned char *buf = (unsigned char *)par->info->screen_base; 869 870 mutex_lock(&(par->io_lock)); 871 /* y1 must be a multiple of 4 so drop the lower bits */ 872 y1 &= 0xFFFC; 873 /* y2 must be a multiple of 4 , but - 1 so up the lower bits */ 874 y2 |= 0x0003; 875 876 args[0] = 0x3 << 4; 877 args[1] = 0; 878 args[2] = y1; 879 args[3] = cpu_to_le16(par->info->var.xres); 880 args[4] = y2; 881 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args); 882 883 args[0] = 0x154; 884 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 885 886 buf += y1 * par->info->var.xres; 887 broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2, 888 (u16 *) buf); 889 890 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 891 892 args[0] = 0x4300; 893 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 894 895 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 896 897 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 898 899 par->board->wait_for_rdy(par); 900 mutex_unlock(&(par->io_lock)); 901 902} 903 904static void broadsheetfb_dpy_update(struct broadsheetfb_par *par) 905{ 906 u16 args[5]; 907 908 mutex_lock(&(par->io_lock)); 909 args[0] = 0x3 << 4; 910 broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args); 911 912 args[0] = 0x154; 913 broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args); 914 broadsheet_burst_write(par, (panel_table[par->panel_index].w * 915 panel_table[par->panel_index].h)/2, 916 (u16 *) par->info->screen_base); 917 918 broadsheet_send_command(par, BS_CMD_LD_IMG_END); 919 920 args[0] = 0x4300; 921 broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args); 922 923 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG); 924 925 broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND); 926 927 par->board->wait_for_rdy(par); 928 mutex_unlock(&(par->io_lock)); 929} 930 931/* this is called back from the deferred io workqueue */ 932static void broadsheetfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist) 933{ 934 u16 y1 = 0, h = 0; 935 unsigned long prev_offset = ULONG_MAX; 936 struct fb_deferred_io_pageref *pageref; 937 int h_inc; 938 u16 yres = info->var.yres; 939 u16 xres = info->var.xres; 940 941 /* height increment is fixed per page */ 942 h_inc = DIV_ROUND_UP(PAGE_SIZE , xres); 943 944 /* walk the written page list and swizzle the data */ 945 list_for_each_entry(pageref, pagereflist, list) { 946 if (prev_offset == ULONG_MAX) { 947 /* just starting so assign first page */ 948 y1 = pageref->offset / xres; 949 h = h_inc; 950 } else if ((prev_offset + PAGE_SIZE) == pageref->offset) { 951 /* this page is consecutive so increase our height */ 952 h += h_inc; 953 } else { 954 /* page not consecutive, issue previous update first */ 955 broadsheetfb_dpy_update_pages(info->par, y1, y1 + h); 956 /* start over with our non consecutive page */ 957 y1 = pageref->offset / xres; 958 h = h_inc; 959 } 960 prev_offset = pageref->offset; 961 } 962 963 /* if we still have any pages to update we do so now */ 964 if (h >= yres) { 965 /* its a full screen update, just do it */ 966 broadsheetfb_dpy_update(info->par); 967 } else { 968 broadsheetfb_dpy_update_pages(info->par, y1, 969 min((u16) (y1 + h), yres)); 970 } 971} 972 973static void broadsheetfb_fillrect(struct fb_info *info, 974 const struct fb_fillrect *rect) 975{ 976 struct broadsheetfb_par *par = info->par; 977 978 sys_fillrect(info, rect); 979 980 broadsheetfb_dpy_update(par); 981} 982 983static void broadsheetfb_copyarea(struct fb_info *info, 984 const struct fb_copyarea *area) 985{ 986 struct broadsheetfb_par *par = info->par; 987 988 sys_copyarea(info, area); 989 990 broadsheetfb_dpy_update(par); 991} 992 993static void broadsheetfb_imageblit(struct fb_info *info, 994 const struct fb_image *image) 995{ 996 struct broadsheetfb_par *par = info->par; 997 998 sys_imageblit(info, image); 999 1000 broadsheetfb_dpy_update(par); 1001} 1002 1003/* 1004 * this is the slow path from userspace. they can seek and write to 1005 * the fb. it's inefficient to do anything less than a full screen draw 1006 */ 1007static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf, 1008 size_t count, loff_t *ppos) 1009{ 1010 struct broadsheetfb_par *par = info->par; 1011 unsigned long p = *ppos; 1012 void *dst; 1013 int err = 0; 1014 unsigned long total_size; 1015 1016 if (info->state != FBINFO_STATE_RUNNING) 1017 return -EPERM; 1018 1019 total_size = info->fix.smem_len; 1020 1021 if (p > total_size) 1022 return -EFBIG; 1023 1024 if (count > total_size) { 1025 err = -EFBIG; 1026 count = total_size; 1027 } 1028 1029 if (count + p > total_size) { 1030 if (!err) 1031 err = -ENOSPC; 1032 1033 count = total_size - p; 1034 } 1035 1036 dst = (void *)(info->screen_base + p); 1037 1038 if (copy_from_user(dst, buf, count)) 1039 err = -EFAULT; 1040 1041 if (!err) 1042 *ppos += count; 1043 1044 broadsheetfb_dpy_update(par); 1045 1046 return (err) ? err : count; 1047} 1048 1049static const struct fb_ops broadsheetfb_ops = { 1050 .owner = THIS_MODULE, 1051 .fb_read = fb_sys_read, 1052 .fb_write = broadsheetfb_write, 1053 .fb_fillrect = broadsheetfb_fillrect, 1054 .fb_copyarea = broadsheetfb_copyarea, 1055 .fb_imageblit = broadsheetfb_imageblit, 1056 .fb_mmap = fb_deferred_io_mmap, 1057}; 1058 1059static struct fb_deferred_io broadsheetfb_defio = { 1060 .delay = HZ/4, 1061 .sort_pagereflist = true, 1062 .deferred_io = broadsheetfb_dpy_deferred_io, 1063}; 1064 1065static int broadsheetfb_probe(struct platform_device *dev) 1066{ 1067 struct fb_info *info; 1068 struct broadsheet_board *board; 1069 int retval = -ENOMEM; 1070 int videomemorysize; 1071 unsigned char *videomemory; 1072 struct broadsheetfb_par *par; 1073 int i; 1074 int dpyw, dpyh; 1075 int panel_index; 1076 1077 /* pick up board specific routines */ 1078 board = dev->dev.platform_data; 1079 if (!board) 1080 return -EINVAL; 1081 1082 /* try to count device specific driver, if can't, platform recalls */ 1083 if (!try_module_get(board->owner)) 1084 return -ENODEV; 1085 1086 info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev); 1087 if (!info) 1088 goto err; 1089 1090 switch (board->get_panel_type()) { 1091 case 37: 1092 panel_index = 1; 1093 break; 1094 case 97: 1095 panel_index = 2; 1096 break; 1097 case 6: 1098 default: 1099 panel_index = 0; 1100 break; 1101 } 1102 1103 dpyw = panel_table[panel_index].w; 1104 dpyh = panel_table[panel_index].h; 1105 1106 videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE); 1107 1108 videomemory = vzalloc(videomemorysize); 1109 if (!videomemory) 1110 goto err_fb_rel; 1111 1112 info->screen_base = (char *)videomemory; 1113 info->fbops = &broadsheetfb_ops; 1114 1115 broadsheetfb_var.xres = dpyw; 1116 broadsheetfb_var.yres = dpyh; 1117 broadsheetfb_var.xres_virtual = dpyw; 1118 broadsheetfb_var.yres_virtual = dpyh; 1119 info->var = broadsheetfb_var; 1120 1121 broadsheetfb_fix.line_length = dpyw; 1122 info->fix = broadsheetfb_fix; 1123 info->fix.smem_len = videomemorysize; 1124 par = info->par; 1125 par->panel_index = panel_index; 1126 par->info = info; 1127 par->board = board; 1128 par->write_reg = broadsheet_write_reg; 1129 par->read_reg = broadsheet_read_reg; 1130 init_waitqueue_head(&par->waitq); 1131 1132 mutex_init(&par->io_lock); 1133 1134 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; 1135 1136 info->fbdefio = &broadsheetfb_defio; 1137 fb_deferred_io_init(info); 1138 1139 retval = fb_alloc_cmap(&info->cmap, 16, 0); 1140 if (retval < 0) { 1141 dev_err(&dev->dev, "Failed to allocate colormap\n"); 1142 goto err_vfree; 1143 } 1144 1145 /* set cmap */ 1146 for (i = 0; i < 16; i++) 1147 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32; 1148 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16); 1149 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16); 1150 1151 retval = par->board->setup_irq(info); 1152 if (retval < 0) 1153 goto err_cmap; 1154 1155 /* this inits the dpy */ 1156 retval = board->init(par); 1157 if (retval < 0) 1158 goto err_free_irq; 1159 1160 broadsheet_identify(par); 1161 1162 broadsheet_init(par); 1163 1164 retval = register_framebuffer(info); 1165 if (retval < 0) 1166 goto err_free_irq; 1167 1168 platform_set_drvdata(dev, info); 1169 1170 retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform); 1171 if (retval < 0) 1172 goto err_unreg_fb; 1173 1174 fb_info(info, "Broadsheet frame buffer, using %dK of video memory\n", 1175 videomemorysize >> 10); 1176 1177 1178 return 0; 1179 1180err_unreg_fb: 1181 unregister_framebuffer(info); 1182err_free_irq: 1183 board->cleanup(par); 1184err_cmap: 1185 fb_dealloc_cmap(&info->cmap); 1186err_vfree: 1187 vfree(videomemory); 1188err_fb_rel: 1189 framebuffer_release(info); 1190err: 1191 module_put(board->owner); 1192 return retval; 1193 1194} 1195 1196static int broadsheetfb_remove(struct platform_device *dev) 1197{ 1198 struct fb_info *info = platform_get_drvdata(dev); 1199 1200 if (info) { 1201 struct broadsheetfb_par *par = info->par; 1202 1203 device_remove_file(info->dev, &dev_attr_loadstore_waveform); 1204 unregister_framebuffer(info); 1205 fb_deferred_io_cleanup(info); 1206 par->board->cleanup(par); 1207 fb_dealloc_cmap(&info->cmap); 1208 vfree((void *)info->screen_base); 1209 module_put(par->board->owner); 1210 framebuffer_release(info); 1211 } 1212 return 0; 1213} 1214 1215static struct platform_driver broadsheetfb_driver = { 1216 .probe = broadsheetfb_probe, 1217 .remove = broadsheetfb_remove, 1218 .driver = { 1219 .name = "broadsheetfb", 1220 }, 1221}; 1222module_platform_driver(broadsheetfb_driver); 1223 1224MODULE_DESCRIPTION("fbdev driver for Broadsheet controller"); 1225MODULE_AUTHOR("Jaya Kumar"); 1226MODULE_LICENSE("GPL");